Color targets: When showing the bookmark screen from within the wps, switch to normal...
[kugel-rb.git] / apps / bookmark.c
blob850514c3453fbf572b2cedc4478d1344526b5852
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 #define MAX_BOOKMARKS 10
55 #define MAX_BOOKMARK_SIZE 350
56 #define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/most-recent.bmark"
58 static bool add_bookmark(const char* bookmark_file_name, const char* bookmark);
59 static bool check_bookmark(const char* bookmark);
60 static char* create_bookmark(void);
61 static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id);
62 static void display_bookmark(const char* bookmark,
63 int bookmark_id,
64 int bookmark_count);
65 static void say_bookmark(const char* bookmark,
66 int bookmark_id);
67 static bool generate_bookmark_file_name(const char *in);
68 static char* get_bookmark(const char* bookmark_file, int bookmark_count);
69 static bool parse_bookmark(const char *bookmark,
70 int *resume_index,
71 int *resume_offset,
72 int *resume_seed,
73 int *resume_first_index,
74 char* resume_file,
75 unsigned int resume_file_size,
76 long* ms,
77 int * repeat_mode,
78 bool *shuffle,
79 char* file_name);
80 static char* select_bookmark(const char* bookmark_file_name);
81 static bool system_check(void);
82 static bool write_bookmark(bool create_bookmark_file);
83 static int get_bookmark_count(const char* bookmark_file_name);
85 static char global_temp_buffer[MAX_PATH+1];
86 static char global_bookmark_file_name[MAX_PATH];
87 static char global_read_buffer[MAX_BOOKMARK_SIZE];
88 static char global_bookmark[MAX_BOOKMARK_SIZE];
89 static char global_filename[MAX_PATH];
91 /* ----------------------------------------------------------------------- */
92 /* This is the interface function from the main menu. */
93 /* ----------------------------------------------------------------------- */
94 bool bookmark_create_menu(void)
96 write_bookmark(true);
97 return false;
100 /* ----------------------------------------------------------------------- */
101 /* This function acts as the load interface from the main menu */
102 /* This function determines the bookmark file name and then loads that file*/
103 /* for the user. The user can then select a bookmark to load. */
104 /* If no file/directory is currently playing, the menu item does not work. */
105 /* ----------------------------------------------------------------------- */
106 bool bookmark_load_menu(void)
108 bool success = true;
109 int offset;
110 int seed;
111 int index;
112 char* bookmark;
114 if(!system_check())
115 return false;
116 else
118 char* name = playlist_get_name(NULL, global_temp_buffer,
119 sizeof(global_temp_buffer));
120 if (generate_bookmark_file_name(name))
122 bookmark = select_bookmark(global_bookmark_file_name);
123 if (!bookmark)
124 return false; /* User exited without selecting a bookmark */
126 success = parse_bookmark(bookmark,
127 &index,
128 &offset,
129 &seed,
130 NULL,
131 global_temp_buffer,
132 sizeof(global_temp_buffer),
133 NULL,
134 &global_settings.repeat_mode,
135 &global_settings.playlist_shuffle,
136 global_filename);
138 else
140 /* something bad happened while creating bookmark name*/
141 success = false;
144 if (success)
145 bookmark_play(global_temp_buffer, index, offset, seed,
146 global_filename);
149 return success;
152 /* ----------------------------------------------------------------------- */
153 /* Gives the user a list of the Most Recent Bookmarks. This is an */
154 /* interface function */
155 /* ----------------------------------------------------------------------- */
156 bool bookmark_mrb_load()
158 bool success = true;
159 int offset;
160 int seed;
161 int index;
162 char* bookmark;
164 bookmark = select_bookmark(RECENT_BOOKMARK_FILE);
165 if (!bookmark)
166 return false; /* User exited without selecting a bookmark */
168 success = parse_bookmark(bookmark,
169 &index,
170 &offset,
171 &seed,
172 NULL,
173 global_temp_buffer,
174 sizeof(global_temp_buffer),
175 NULL,
176 &global_settings.repeat_mode,
177 &global_settings.playlist_shuffle,
178 global_filename);
180 if (success)
181 bookmark_play(global_temp_buffer, index, offset, seed,
182 global_filename);
184 return success;
188 /* ----------------------------------------------------------------------- */
189 /* This function handles an autobookmark creation. This is an interface */
190 /* function. */
191 /* ----------------------------------------------------------------------- */
192 bool bookmark_autobookmark(void)
194 if (!system_check())
195 return false;
197 audio_pause(); /* first pause playback */
198 switch (global_settings.autocreatebookmark)
200 case BOOKMARK_YES:
201 return write_bookmark(true);
203 case BOOKMARK_NO:
204 return false;
206 case BOOKMARK_RECENT_ONLY_YES:
207 return write_bookmark(false);
209 #ifdef HAVE_LCD_BITMAP
210 unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY)};
211 struct text_message message={(char **)lines, 1};
212 #else
213 unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY),
214 str(LANG_RESUME_CONFIRM_PLAYER)};
215 struct text_message message={(char **)lines, 2};
216 #endif
217 #ifdef HAVE_LCD_COLOR
218 show_main_backdrop(); /* switch to main backdrop as we may come from wps */
219 #endif
220 gui_syncstatusbar_draw(&statusbars, false);
221 if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
223 if (global_settings.autocreatebookmark == BOOKMARK_RECENT_ONLY_ASK)
224 return write_bookmark(false);
225 else
226 return write_bookmark(true);
228 return false;
231 /* ----------------------------------------------------------------------- */
232 /* This function takes the current current resume information and writes */
233 /* that to the beginning of the bookmark file. */
234 /* This file will contain N number of bookmarks in the following format: */
235 /* resume_index*resume_offset*resume_seed*resume_first_index* */
236 /* resume_file*milliseconds*MP3 Title* */
237 /* ------------------------------------------------------------------------*/
238 static bool write_bookmark(bool create_bookmark_file)
240 bool success=false;
241 char* bookmark;
243 if (!system_check())
244 return false; /* something didn't happen correctly, do nothing */
246 bookmark = create_bookmark();
247 if (!bookmark)
248 return false; /* something didn't happen correctly, do nothing */
250 if (global_settings.usemrb)
251 success = add_bookmark(RECENT_BOOKMARK_FILE, bookmark);
254 /* writing the bookmark */
255 if (create_bookmark_file)
257 char* name = playlist_get_name(NULL, global_temp_buffer,
258 sizeof(global_temp_buffer));
259 if (generate_bookmark_file_name(name))
261 success = add_bookmark(global_bookmark_file_name, bookmark);
265 if (success)
266 gui_syncsplash(HZ, true, str(LANG_BOOKMARK_CREATE_SUCCESS));
267 else
268 gui_syncsplash(HZ, true, str(LANG_BOOKMARK_CREATE_FAILURE));
270 return true;
273 /* ----------------------------------------------------------------------- */
274 /* This function adds a bookmark to a file. */
275 /* ------------------------------------------------------------------------*/
276 static bool add_bookmark(const char* bookmark_file_name, const char* bookmark)
278 int temp_bookmark_file = 0;
279 int bookmark_file = 0;
280 int bookmark_count = 0;
281 char* playlist = NULL;
282 char* cp;
283 char* tmp;
284 int len = 0;
285 bool unique = false;
287 /* Opening up a temp bookmark file */
288 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
289 "%s.tmp", bookmark_file_name);
290 temp_bookmark_file = open(global_temp_buffer,
291 O_WRONLY | O_CREAT | O_TRUNC);
292 if (temp_bookmark_file < 0)
293 return false; /* can't open the temp file */
295 if (!strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE) &&
296 (global_settings.usemrb == BOOKMARK_UNIQUE_ONLY))
298 playlist = strchr(bookmark,'/');
299 cp = strrchr(bookmark,';');
300 len = cp - playlist;
301 unique = true;
304 /* Writing the new bookmark to the begining of the temp file */
305 write(temp_bookmark_file, bookmark, strlen(bookmark));
306 write(temp_bookmark_file, "\n", 1);
307 bookmark_count++;
309 /* Reading in the previous bookmarks and writing them to the temp file */
310 bookmark_file = open(bookmark_file_name, O_RDONLY);
311 if (bookmark_file >= 0)
313 while (read_line(bookmark_file, global_read_buffer,
314 sizeof(global_read_buffer)))
316 /* The MRB has a max of MAX_BOOKMARKS in it */
317 /* This keeps it from getting too large */
318 if ((strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE)==0))
320 if(bookmark_count >= MAX_BOOKMARKS)
321 break;
324 cp = strchr(global_read_buffer,'/');
325 tmp = strrchr(global_read_buffer,';');
326 if (check_bookmark(global_read_buffer) &&
327 (!unique || len != tmp -cp || strncmp(playlist,cp,len)))
329 bookmark_count++;
330 write(temp_bookmark_file, global_read_buffer,
331 strlen(global_read_buffer));
332 write(temp_bookmark_file, "\n", 1);
335 close(bookmark_file);
337 close(temp_bookmark_file);
339 remove(bookmark_file_name);
340 rename(global_temp_buffer, bookmark_file_name);
342 return true;
346 /* ----------------------------------------------------------------------- */
347 /* This function takes the system resume data and formats it into a valid */
348 /* bookmark. */
349 /* ----------------------------------------------------------------------- */
350 static char* create_bookmark()
352 int resume_index = 0;
353 char *file;
355 /* grab the currently playing track */
356 struct mp3entry *id3 = audio_current_track();
357 if(!id3)
358 return NULL;
360 /* Get some basic resume information */
361 /* queue_resume and queue_resume_index are not used and can be ignored.*/
362 playlist_get_resume_info(&resume_index);
364 /* Get the currently playing file minus the path */
365 /* This is used when displaying the available bookmarks */
366 file = strrchr(id3->path,'/');
367 if(NULL == file)
368 return NULL;
370 /* create the bookmark */
371 snprintf(global_bookmark, sizeof(global_bookmark),
372 "%d;%ld;%d;%d;%ld;%d;%d;%s;%s",
373 resume_index,
374 id3->offset,
375 playlist_get_seed(NULL),
377 id3->elapsed,
378 global_settings.repeat_mode,
379 global_settings.playlist_shuffle,
380 playlist_get_name(NULL, global_temp_buffer,
381 sizeof(global_temp_buffer)),
382 file+1);
384 /* checking to see if the bookmark is valid */
385 if (check_bookmark(global_bookmark))
386 return global_bookmark;
387 else
388 return NULL;
391 static bool check_bookmark(const char* bookmark)
393 return parse_bookmark(bookmark,
394 NULL,NULL,NULL, NULL,
395 NULL,0,NULL,NULL,
396 NULL, NULL);
399 /* ----------------------------------------------------------------------- */
400 /* This function will determine if an autoload is necessary. This is an */
401 /* interface function. */
402 /* ------------------------------------------------------------------------*/
403 bool bookmark_autoload(const char* file)
405 int key;
406 int fd;
407 bool done = false;
409 if(global_settings.autoloadbookmark == BOOKMARK_NO)
410 return false;
412 /*Checking to see if a bookmark file exists.*/
413 if(!generate_bookmark_file_name(file))
415 return false;
417 fd = open(global_bookmark_file_name, O_RDONLY);
418 if(fd<0)
419 return false;
420 if(-1 == lseek(fd, 0, SEEK_END))
422 close(fd);
423 return false;
425 close(fd);
426 if(global_settings.autoloadbookmark == BOOKMARK_YES)
428 return bookmark_load(global_bookmark_file_name, true);
430 else
432 /* Prompting user to confirm bookmark load */
433 lcd_clear_display();
434 gui_syncstatusbar_draw(&statusbars, false);
435 #ifdef HAVE_LCD_BITMAP
436 lcd_setmargins(0, STATUSBAR_HEIGHT);
437 lcd_puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY));
438 lcd_puts(0,1, str(LANG_CONFIRM_WITH_PLAY_RECORDER));
439 lcd_puts(0,2, str(LANG_BOOKMARK_SELECT_LIST_BOOKMARKS));
440 lcd_puts(0,3, str(LANG_CANCEL_WITH_ANY_RECORDER));
441 #else
442 lcd_puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY));
443 lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
444 #endif
445 lcd_update();
447 while(!done)
449 /* Wait for a key to be pushed */
450 key = button_get(true);
451 switch(key)
453 #ifdef HAVE_LCD_BITMAP
454 case BOOKMARK_DOWN:
455 return bookmark_load(global_bookmark_file_name, false);
456 #endif
457 case SETTINGS_OK:
458 return bookmark_load(global_bookmark_file_name, true);
460 default:
461 /* Handle sys events, ignore button releases & repeats */
462 if (default_event_handler(key) ||
463 !(key & (BUTTON_REPEAT|BUTTON_REL)))
464 done = true;
465 break;
468 return false;
472 /* ----------------------------------------------------------------------- */
473 /* This function loads the bookmark information into the resume memory. */
474 /* This is an interface function. */
475 /* ------------------------------------------------------------------------*/
476 bool bookmark_load(const char* file, bool autoload)
478 int fd;
479 bool success = true;
480 int offset;
481 int seed;
482 int index;
483 char* bookmark = NULL;;
485 if(autoload)
487 fd = open(file, O_RDONLY);
488 if(fd >= 0)
490 if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)))
491 bookmark=global_read_buffer;
492 close(fd);
495 else
497 /* This is not an auto-load, so list the bookmarks */
498 bookmark=select_bookmark(file);
499 if(!bookmark)
500 return true; /* User exited without selecting a bookmark */
503 if(bookmark)
505 success = parse_bookmark(bookmark,
506 &index,
507 &offset,
508 &seed,
509 NULL,
510 global_temp_buffer,
511 sizeof(global_temp_buffer),
512 NULL,
513 &global_settings.repeat_mode,
514 &global_settings.playlist_shuffle,
515 global_filename);
519 if(success)
520 bookmark_play(global_temp_buffer, index, offset, seed,
521 global_filename);
523 return success;
527 static int get_bookmark_count(const char* bookmark_file_name)
529 int read_count = 0;
530 int file = open(bookmark_file_name, O_RDONLY);
532 if(file < 0)
533 return -1;
535 /* Get the requested bookmark */
536 while(read_line(file, global_read_buffer, sizeof(global_read_buffer)))
538 if(check_bookmark(global_read_buffer))
539 read_count++;
542 close(file);
543 return read_count;
548 /* ----------------------------------------------------------------------- */
549 /* This displays a the bookmarks in a file and allows the user to */
550 /* select one to play. */
551 /* ------------------------------------------------------------------------*/
552 static char* select_bookmark(const char* bookmark_file_name)
554 int bookmark_id = 0;
555 int bookmark_id_prev = -1;
556 int key;
557 int lastkey = BUTTON_NONE;
558 char* bookmark = NULL;
559 int bookmark_count = 0;
561 #ifdef HAVE_LCD_BITMAP
562 int x = lcd_getxmargin();
563 int y = lcd_getymargin();
564 lcd_setmargins(0, 0);
565 #endif
567 bookmark_count = get_bookmark_count(bookmark_file_name);
569 while(true)
571 if(bookmark_id < 0)
572 bookmark_id = bookmark_count -1;
573 if(bookmark_id >= bookmark_count)
574 bookmark_id = 0;
576 if (bookmark_id != bookmark_id_prev)
578 bookmark = get_bookmark(bookmark_file_name, bookmark_id);
579 bookmark_id_prev = bookmark_id;
582 if (!bookmark)
584 /* if there were no bookmarks in the file, delete the file and exit. */
585 if(bookmark_id <= 0)
587 gui_syncsplash(HZ, true, str(LANG_BOOKMARK_LOAD_EMPTY));
588 remove(bookmark_file_name);
589 return NULL;
591 else
593 bookmark_id_prev = bookmark_id;
594 bookmark_id--;
597 else
599 display_bookmark(bookmark, bookmark_id, bookmark_count);
600 if (global_settings.talk_menu) /* for voice UI */
601 say_bookmark(bookmark, bookmark_id);
604 /* waiting for the user to click a button */
605 key = button_get(true);
606 switch(key)
608 case BOOKMARK_SELECT:
609 #ifdef BOOKMARK_SELECT_PRE
610 if (lastkey != BOOKMARK_SELECT_PRE)
611 break;
612 #endif
613 /* User wants to use this bookmark */
614 #ifdef HAVE_LCD_BITMAP
615 if (global_settings.statusbar)
616 lcd_setmargins(0, STATUSBAR_HEIGHT);
617 else
618 lcd_setmargins(0, 0);
619 #endif
620 return bookmark;
622 case BOOKMARK_DELETE:
623 /* User wants to delete this bookmark */
624 delete_bookmark(bookmark_file_name, bookmark_id);
625 bookmark_id_prev=-2;
626 bookmark_count--;
627 if(bookmark_id >= bookmark_count)
628 bookmark_id = bookmark_count -1;
629 break;
631 case SETTINGS_DEC:
632 case SETTINGS_DEC | BUTTON_REPEAT:
633 bookmark_id--;
634 break;
636 case SETTINGS_INC:
637 case SETTINGS_INC | BUTTON_REPEAT:
638 bookmark_id++;
639 break;
641 case SETTINGS_CANCEL:
642 #ifdef SETTINGS_CANCEL2
643 case SETTINGS_CANCEL2:
644 #endif
645 #ifdef SETTINGS_OK2
646 case SETTINGS_OK2:
647 #endif
648 #ifdef HAVE_LCD_BITMAP
649 lcd_setmargins(x, y);
650 #endif
651 return NULL;
653 default:
654 if(default_event_handler(key) == SYS_USB_CONNECTED)
655 return NULL;
656 break;
658 lastkey = key;
661 return NULL;
665 /* ----------------------------------------------------------------------- */
666 /* This function takes a location in a bookmark file and deletes that */
667 /* bookmark. */
668 /* ------------------------------------------------------------------------*/
669 static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id)
671 int temp_bookmark_file = 0;
672 int bookmark_file = 0;
673 int bookmark_count = 0;
675 /* Opening up a temp bookmark file */
676 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
677 "%s.tmp", bookmark_file_name);
678 temp_bookmark_file = open(global_temp_buffer,
679 O_WRONLY | O_CREAT | O_TRUNC);
680 bookmark_file = open(bookmark_file_name, O_RDONLY);
682 if (temp_bookmark_file < 0 || bookmark_file < 0)
683 return false; /* can't open one of the files */
685 /* Reading in the previous bookmarks and writing them to the temp file */
686 while (read_line(bookmark_file, global_read_buffer,
687 sizeof(global_read_buffer)))
689 /* The MRB has a max of MAX_BOOKMARKS in it */
690 /* This keeps it from getting too large */
691 if ((strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE)==0))
693 if(bookmark_count >= MAX_BOOKMARKS)
694 break;
697 if (check_bookmark(global_read_buffer))
699 if (bookmark_id != bookmark_count)
701 write(temp_bookmark_file, global_read_buffer,
702 strlen(global_read_buffer));
703 write(temp_bookmark_file, "\n", 1);
705 bookmark_count++;
709 close(bookmark_file);
710 close(temp_bookmark_file);
712 remove(bookmark_file_name);
713 rename(global_temp_buffer, bookmark_file_name);
715 return true;
718 /* ----------------------------------------------------------------------- */
719 /* This function parses a bookmark and displays it for the user. */
720 /* ------------------------------------------------------------------------*/
721 static void display_bookmark(const char* bookmark,
722 int bookmark_id,
723 int bookmark_count)
725 int resume_index = 0;
726 long ms = 0;
727 int repeat_mode = 0;
728 bool playlist_shuffle = false;
729 int len;
730 char *dot;
732 /* getting the index and the time into the file */
733 parse_bookmark(bookmark,
734 &resume_index, NULL, NULL, NULL, NULL, 0,
735 &ms, &repeat_mode, &playlist_shuffle,
736 global_filename);
738 lcd_clear_display();
739 lcd_stop_scroll();
741 #ifdef HAVE_LCD_BITMAP
742 /* bookmark shuffle and repeat states*/
743 switch (repeat_mode)
745 #if (AB_REPEAT_ENABLE == 1)
746 case REPEAT_AB:
747 statusbar_icon_play_mode(Icon_RepeatAB);
748 break;
749 #endif
751 case REPEAT_ONE:
752 statusbar_icon_play_mode(Icon_RepeatOne);
753 break;
755 case REPEAT_ALL:
756 statusbar_icon_play_mode(Icon_Repeat);
757 break;
759 if(playlist_shuffle)
760 statusbar_icon_shuffle();
762 /* File Name */
763 len=strlen(global_filename);
764 if (len>3)
765 dot=strrchr(global_filename + len - 4, '.');
766 else
767 dot=NULL;
768 if (dot)
769 *dot='\0';
770 lcd_puts_scroll(0, 0, (unsigned char *)global_filename);
771 if (dot)
772 *dot='.';
774 /* bookmark number */
775 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d/%2d",
776 str(LANG_BOOKMARK_SELECT_BOOKMARK_TEXT),
777 bookmark_id + 1, bookmark_count);
778 lcd_puts_scroll(0, 1, (unsigned char *)global_temp_buffer);
780 /* bookmark resume index */
781 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d",
782 str(LANG_BOOKMARK_SELECT_INDEX_TEXT), resume_index+1);
783 lcd_puts_scroll(0, 2, (unsigned char *)global_temp_buffer);
785 /* elapsed time*/
786 if ( ms < 3600000 )
788 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %ld:%02d",
789 str(LANG_BOOKMARK_SELECT_TIME_TEXT),
790 ms / 60000,
791 (unsigned int)(ms % 60000) / 1000);
792 /* unsigned int: hinting for 16bits archs */
794 else
796 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
797 "%s: %ld:%02ld:%02d",
798 str(LANG_BOOKMARK_SELECT_TIME_TEXT),
799 ms / 3600000,
800 ms % 3600000 / 60000,
801 (unsigned int)(ms % 60000) / 1000);
803 lcd_puts_scroll(0, 3, (unsigned char *)global_temp_buffer);
805 /* commands */
806 lcd_puts_scroll(0, 4, str(LANG_BOOKMARK_SELECT_PLAY));
807 lcd_puts_scroll(0, 5, str(LANG_BOOKMARK_SELECT_EXIT));
808 lcd_puts_scroll(0, 6, str(LANG_BOOKMARK_SELECT_DELETE));
809 #else
810 (void)bookmark_id;
811 len=strlen(global_filename);
812 if (len>3)
813 dot=strrchr(global_filename+len-4,'.');
814 else
815 dot=NULL;
816 if (dot)
817 *dot='\0';
818 if ( ms < 3600000 )
820 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
821 "%2d, %ld:%02ld, %s,",
822 (bookmark_count+1),
823 ms / 60000,
824 ms % 60000 / 1000,
825 global_filename);
827 else
829 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
830 "%2d, %ld:%02ld:%02ld, %s,",
831 (bookmark_count+1),
832 ms / 60000,
833 ms % 3600000 / 60000,
834 ms % 60000 / 1000,
835 global_filename);
838 gui_syncstatusbar_draw(&statusbars, false);
839 lcd_puts_scroll(0,0,global_temp_buffer);
840 lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
841 if (dot)
842 *dot='.';
843 #endif
844 lcd_update();
848 /* ----------------------------------------------------------------------- */
849 /* This function parses a bookmark, says the voice UI part of it. */
850 /* ------------------------------------------------------------------------*/
851 static void say_bookmark(const char* bookmark,
852 int bookmark_id)
854 int resume_index;
855 long ms;
856 char dir[MAX_PATH];
857 bool enqueue = false; /* only the first voice is not queued */
859 parse_bookmark(bookmark,
860 &resume_index,
861 NULL, NULL, NULL,
862 dir, sizeof(dir),
863 &ms, NULL, NULL,
864 NULL);
865 /* disabled, because transition between talkbox and voice UI clip is not nice */
866 #if 0
867 if (global_settings.talk_dir >= 3)
868 { /* "talkbox" enabled */
869 char* last = strrchr(dir, '/');
870 if (last)
871 { /* compose filename for talkbox */
872 strncpy(last + 1, dir_thumbnail_name, sizeof(dir)-(last-dir)-1);
873 talk_file(dir, enqueue);
874 enqueue = true;
877 #endif
878 talk_id(VOICE_EXT_BMARK, enqueue);
879 talk_number(bookmark_id + 1, true);
880 talk_id(LANG_BOOKMARK_SELECT_INDEX_TEXT, true);
881 talk_number(resume_index + 1, true);
882 talk_id(LANG_BOOKMARK_SELECT_TIME_TEXT, true);
883 if (ms / 60000)
884 talk_value(ms / 60000, UNIT_MIN, true);
885 talk_value((ms % 60000) / 1000, UNIT_SEC, true);
889 /* ----------------------------------------------------------------------- */
890 /* This function retrieves a given bookmark from a file. */
891 /* If the bookmark requested is beyond the number of bookmarks available */
892 /* in the file, it will return the last one. */
893 /* It also returns the index number of the bookmark in the file */
894 /* ------------------------------------------------------------------------*/
895 static char* get_bookmark(const char* bookmark_file, int bookmark_count)
897 int read_count = -1;
898 int result = 0;
899 int file = open(bookmark_file, O_RDONLY);
901 if (file < 0)
902 return NULL;
904 if (bookmark_count < 0)
905 return NULL;
907 /* Get the requested bookmark */
908 while (read_count < bookmark_count)
910 /*Reading in a single bookmark */
911 result = read_line(file,
912 global_read_buffer,
913 sizeof(global_read_buffer));
915 /* Reading past the last bookmark in the file
916 causes the loop to stop */
917 if (result <= 0)
918 break;
920 read_count++;
923 close(file);
924 if (read_count == bookmark_count)
925 return global_read_buffer;
926 else
927 return NULL;
930 /* ----------------------------------------------------------------------- */
931 /* This function takes a bookmark and parses it. This function also */
932 /* validates the bookmark. Passing in NULL for an output variable */
933 /* indicates that value is not requested. */
934 /* ----------------------------------------------------------------------- */
935 static bool parse_bookmark(const char *bookmark,
936 int *resume_index,
937 int *resume_offset,
938 int *resume_seed,
939 int *resume_first_index,
940 char* resume_file,
941 unsigned int resume_file_size,
942 long* ms,
943 int * repeat_mode, bool *shuffle,
944 char* file_name)
946 /* First check to see if a valid line was passed in. */
947 int bookmark_len = strlen(bookmark);
948 int local_resume_index = 0;
949 int local_resume_offset = 0;
950 int local_resume_seed = 0;
951 int local_resume_first_index = 0;
952 int local_mS = 0;
953 int local_shuffle = 0;
954 int local_repeat_mode = 0;
955 char* local_resume_file = NULL;
956 char* local_file_name = NULL;
957 char* field;
958 char* end;
959 static char bookmarkcopy[MAX_BOOKMARK_SIZE];
961 /* Don't do anything if the bookmark length is 0 */
962 if (bookmark_len <= 0)
963 return false;
965 /* Making a dup of the bookmark to use with strtok_r */
966 strncpy(bookmarkcopy, bookmark, sizeof(bookmarkcopy));
967 bookmarkcopy[sizeof(bookmarkcopy) - 1] = 0;
969 /* resume_index */
970 if ((field = strtok_r(bookmarkcopy, ";", &end)))
971 local_resume_index = atoi(field);
972 else
973 return false;
975 /* resume_offset */
976 if ((field = strtok_r(NULL, ";", &end)))
977 local_resume_offset = atoi(field);
978 else
979 return false;
981 /* resume_seed */
982 if ((field = strtok_r(NULL, ";", &end)))
983 local_resume_seed = atoi(field);
984 else
985 return false;
987 /* resume_first_index */
988 if ((field = strtok_r(NULL, ";", &end)))
989 local_resume_first_index = atoi(field);
990 else
991 return false;
993 /* Milliseconds into MP3. Used for the bookmark select menu */
994 if ((field = strtok_r(NULL, ";", &end)))
995 local_mS = atoi(field);
996 else
997 return false;
999 /* repeat_mode */
1000 if ((field = strtok_r(NULL, ";", &end)))
1001 local_repeat_mode = atoi(field);
1002 else
1003 return false;
1005 /* shuffle mode */
1006 if ((field = strtok_r(NULL, ";", &end)))
1007 local_shuffle = atoi(field);
1008 else
1009 return false;
1011 /* resume_file & file_name (for the bookmark select menu)*/
1012 if (end)
1014 local_resume_file = strtok_r(NULL, ";", &end);
1016 if (end)
1017 local_file_name = strtok_r(NULL, ";", &end);
1019 else
1020 return false;
1022 /* Only return the values the calling function wants */
1023 if (resume_index)
1024 *resume_index = local_resume_index;
1026 if (resume_offset)
1027 *resume_offset = local_resume_offset;
1029 if (resume_seed)
1030 *resume_seed = local_resume_seed;
1032 if (resume_first_index)
1033 *resume_first_index = local_resume_first_index;
1035 if (resume_file && local_resume_file)
1037 strncpy(resume_file, local_resume_file,
1038 MIN(strlen(local_resume_file), resume_file_size-1));
1039 resume_file[MIN(strlen(local_resume_file), resume_file_size-1)]=0;
1042 if (ms)
1043 *ms = local_mS;
1045 if (shuffle)
1046 *shuffle = local_shuffle;
1048 if (repeat_mode)
1049 *repeat_mode = local_repeat_mode;
1051 if (file_name && local_file_name)
1053 strncpy(file_name, local_file_name,MAX_PATH-1);
1054 file_name[MAX_PATH-1] = 0;
1057 return true;
1060 /* ----------------------------------------------------------------------- */
1061 /* This function is used by multiple functions and is used to generate a */
1062 /* bookmark named based off of the input. */
1063 /* Changing this function could result in how the bookmarks are stored. */
1064 /* it would be here that the centralized/decentralized bookmark code */
1065 /* could be placed. */
1066 /* ----------------------------------------------------------------------- */
1067 static bool generate_bookmark_file_name(const char *in)
1069 int len = strlen(in);
1071 /* if this is a root dir MP3, rename the bookmark file root_dir.bmark */
1072 /* otherwise, name it based on the in variable */
1073 if (!strcmp("/", in))
1074 strcpy(global_bookmark_file_name, "/root_dir.bmark");
1075 else
1077 strcpy(global_bookmark_file_name, in);
1078 if(global_bookmark_file_name[len-1] == '/')
1079 len--;
1080 strcpy(&global_bookmark_file_name[len], ".bmark");
1083 return true;
1086 /* ----------------------------------------------------------------------- */
1087 /* Returns the bookmark name for the current playlist */
1088 /* ----------------------------------------------------------------------- */
1089 bool bookmark_exist(void)
1091 bool exist=false;
1093 if(system_check())
1095 char* name = playlist_get_name(NULL, global_temp_buffer,
1096 sizeof(global_temp_buffer));
1097 if (generate_bookmark_file_name(name))
1099 int fd=open(global_bookmark_file_name, O_RDONLY);
1100 if (fd >=0)
1102 close(fd);
1103 exist=true;
1108 return exist;
1111 /* ----------------------------------------------------------------------- */
1112 /* Checks the current state of the system and returns if it is in a */
1113 /* bookmarkable state. */
1114 /* ----------------------------------------------------------------------- */
1115 /* Inputs: */
1116 /* ----------------------------------------------------------------------- */
1117 /* Outputs: */
1118 /* return bool: Indicates if the system was in a bookmarkable state */
1119 /* ----------------------------------------------------------------------- */
1120 static bool system_check(void)
1122 int resume_index = 0;
1123 struct mp3entry *id3 = audio_current_track();
1125 if (!id3)
1127 /* no track playing */
1128 return false;
1131 /* Checking to see if playing a queued track */
1132 if (playlist_get_resume_info(&resume_index) == -1)
1134 /* something bad happened while getting the queue information */
1135 return false;
1137 else if (playlist_modified(NULL))
1139 /* can't bookmark while in the queue */
1140 return false;
1143 return true;