diff --git a/apps/lang/english.lang b/apps/lang/english.lang index dd8ed84caf..7da2cc2959 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -12716,3 +12716,31 @@ *: "Automatic resume" + + id: LANG_AUTORESUME_AUTOMATIC + desc: resume on automatic track change + user: core + + *: "Resume on automatic track change" + + + *: "Resume on automatic track change" + + + *: "Resume on automatic track change" + + + + id: LANG_AUTORESUME_CUSTOM + desc: enable customization of resume on automatic track change + user: core + + *: "Custom path/genre substrings (comma-separated)" + + + *: "Custom path/genre substrings (comma-separated)" + + + *: "Custom path/genre substrings (comma-separated)" + + diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index ce03e1a646..363792870d 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -28,6 +28,7 @@ #include "action.h" #include "settings.h" #include "menu.h" +#include "keyboard.h" #include "sound_menu.h" #include "exported_menus.h" #include "tree.h" @@ -367,6 +368,64 @@ MAKE_MENU(bookmark_settings_menu, ID2P(LANG_BOOKMARK_SETTINGS), 0, /* BOOKMARK MENU */ /***********************************/ +/***********************************/ +/* AUTORESUME MENU */ +#ifdef HAVE_TAGCACHE +#if CONFIG_CODEC == SWCODEC + +static int autoresume_callback(int action, const struct menu_item_ex *this_item) +{ + (void)this_item; + + if (action == ACTION_EXIT_MENUITEM /* on exit */ + && global_settings.autoresume_enable + && !tagcache_is_usable()) + { + static const char *lines[] = {ID2P(LANG_TAGCACHE_BUSY), + ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; + static const struct text_message message = {lines, 2}; + + if (gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES) + tagcache_rebuild_with_splash(); + } + return action; +} + +static int autoresume_nexttrack_callback(int action, + const struct menu_item_ex *this_item) +{ + (void)this_item; + static int oldval = 0; + switch (action) + { + case ACTION_ENTER_MENUITEM: + oldval = global_settings.autoresume_automatic; + break; + case ACTION_EXIT_MENUITEM: + if (global_settings.autoresume_automatic == AUTORESUME_NEXTTRACK_CUSTOM + && kbd_input ((char*) &global_settings.autoresume_strpat, + MAX_PATHNAME+1) < 0) + { + global_settings.autoresume_automatic = oldval; + } + } + return action; +} + +MENUITEM_SETTING(autoresume_enable, &global_settings.autoresume_enable, + autoresume_callback); +MENUITEM_SETTING(autoresume_automatic, &global_settings.autoresume_automatic, + autoresume_nexttrack_callback); + +MAKE_MENU(autoresume_menu, ID2P(LANG_AUTORESUME), + 0, Icon_NOICON, + &autoresume_enable, &autoresume_automatic); + +#endif /* CONFIG_CODEC == SWCODEC */ +#endif /* HAVE_TAGCACHE */ +/* AUTORESUME MENU */ +/***********************************/ + /***********************************/ /* VOICE MENU */ static int talk_callback(int action,const struct menu_item_ex *this_item); @@ -425,31 +484,6 @@ MAKE_MENU(hotkey_menu, ID2P(LANG_HOTKEY), 0, Icon_NOICON, /***********************************/ /* SETTINGS MENU */ -#ifdef HAVE_TAGCACHE -#if CONFIG_CODEC == SWCODEC -static int autoresume_callback(int action, const struct menu_item_ex *this_item) -{ - (void)this_item; - - if (action == ACTION_EXIT_MENUITEM /* on exit */ - && global_settings.autoresume_enable - && !tagcache_is_usable()) - { - static const char *lines[] = {ID2P(LANG_TAGCACHE_BUSY), - ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; - static const struct text_message message = {lines, 2}; - - if (gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES) - tagcache_rebuild_with_splash(); - } - return action; -} - -MENUITEM_SETTING(autoresume_enable, &global_settings.autoresume_enable, - autoresume_callback); -#endif -#endif - static struct browse_folder_info langs = { LANG_DIR, SHOW_LNG }; MENUITEM_FUNCTION(browse_langs, MENU_FUNC_USEPARAM, ID2P(LANG_LANGUAGE), @@ -465,7 +499,7 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0, &bookmark_settings_menu, #ifdef HAVE_TAGCACHE #if CONFIG_CODEC == SWCODEC - &autoresume_enable, + &autoresume_menu, #endif #endif &browse_langs, &voice_settings_menu, diff --git a/apps/metadata.c b/apps/metadata.c index 47c0e7449b..da20a0df2b 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -25,6 +25,7 @@ #include "debug.h" #include "logf.h" +#include "settings.h" #include "cuesheet.h" #include "metadata.h" @@ -425,3 +426,49 @@ void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig) memcpy(dest, orig, sizeof(struct mp3entry)); adjust_mp3entry(dest, dest, orig); } + +#ifdef HAVE_TAGCACHE +#if CONFIG_CODEC == SWCODEC + +enum { AUTORESUMABLE_UNKNOWN = 0, AUTORESUMABLE_TRUE, AUTORESUMABLE_FALSE }; + +bool autoresumable(struct mp3entry *id3) +{ + unsigned char search[MAX_PATHNAME+1]; + char *saveptr, *substr; + bool is_resumable; + + if (id3->autoresumable) /* result cached? */ + return id3->autoresumable == AUTORESUMABLE_TRUE; + + is_resumable = true; + + strcpy(search, global_settings.autoresume_strpat); + + for (substr = strtok_r(search, ",", &saveptr); + substr; + substr = strtok_r(NULL, ",", &saveptr)) + { + if (id3->path && strcasestr(id3->path, substr)) + goto out; + if (id3->genre_string && strcasestr(id3->genre_string, substr)) + goto out; + } + + is_resumable = false; + + out: + /* cache result */ + id3->autoresumable = + is_resumable ? AUTORESUMABLE_TRUE : AUTORESUMABLE_FALSE; + + logf("autoresumable: %s with genre %s is%s resumable", + id3->path, + id3->genre_string ? id3->genre_string : "(NULL)", + is_resumable ? "" : " not"); + + return is_resumable; +} + +#endif /* SWCODEC */ +#endif /* HAVE_TAGCACHE */ diff --git a/apps/metadata.h b/apps/metadata.h index 3831062418..b99d4d09d6 100644 --- a/apps/metadata.h +++ b/apps/metadata.h @@ -255,6 +255,8 @@ struct mp3entry { int index; /* playlist index */ #ifdef HAVE_TAGCACHE + unsigned char autoresumable; /* caches result of autoresumable() */ + /* runtime database fields */ long tagcache_idx; /* 0=invalid, otherwise idx+1 */ int rating; @@ -287,10 +289,15 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname); bool mp3info(struct mp3entry *entry, const char *filename); void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig); void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig); + #if CONFIG_CODEC == SWCODEC void strip_tags(int handle_id); #endif +#ifdef HAVE_TAGCACHE +bool autoresumable(struct mp3entry *id3); +#endif + #endif diff --git a/apps/playback.c b/apps/playback.c index e33a4ac507..fe7b74893a 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -1002,8 +1002,13 @@ static void audio_update_trackinfo(void) thistrack_id3->elapsed = 0; #ifdef HAVE_TAGCACHE - /* Resume all manually selected tracks if so configured */ - resume = global_settings.autoresume_enable && !automatic_skip; + /* Ignoring resume position for automatic track change if so configured */ + resume = global_settings.autoresume_enable && + (!automatic_skip /* Resume all manually selected tracks */ + || global_settings.autoresume_automatic == AUTORESUME_NEXTTRACK_ALWAYS + || (global_settings.autoresume_automatic != AUTORESUME_NEXTTRACK_NEVER + /* Not never resume? */ + && autoresumable(thistrack_id3))); /* Pass Resume filter? */ #endif if (!resume) diff --git a/apps/settings.h b/apps/settings.h index 131ff181dd..ae32a65bc6 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -125,6 +125,10 @@ enum { SHOW_PATH_OFF = 0, SHOW_PATH_CURRENT, SHOW_PATH_FULL }; /* scrollbar visibility/position */ enum { SCROLLBAR_OFF = 0, SCROLLBAR_LEFT, SCROLLBAR_RIGHT }; +/* autoresume settings */ +enum { AUTORESUME_NEXTTRACK_NEVER = 0, AUTORESUME_NEXTTRACK_ALWAYS, + AUTORESUME_NEXTTRACK_CUSTOM}; + /* Alarm settings */ #ifdef HAVE_RTC_ALARM enum { ALARM_START_WPS = 0, @@ -577,6 +581,9 @@ struct user_settings #endif bool tagcache_autoupdate; /* automatically keep tagcache in sync? */ bool autoresume_enable; /* enable auto-resume feature? */ + int autoresume_automatic; /* resume next track? 0=never, 1=always, + 2=custom */ + unsigned char autoresume_strpat[MAX_PATHNAME+1]; /* comma-separated list */ bool runtimedb; /* runtime database active? */ #endif /* HAVE_TAGCACHE */ diff --git a/apps/settings_list.c b/apps/settings_list.c index 0521d4fb90..75e989eb10 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -1261,6 +1261,15 @@ const struct settings_list settings[] = { BOOL_SETTING(0, autoresume_enable, LANG_AUTORESUME, false, "autoresume enable", off_on, LANG_SET_BOOL_YES, LANG_SET_BOOL_NO, NULL), + CHOICE_SETTING(0, autoresume_automatic, LANG_AUTORESUME_AUTOMATIC, + AUTORESUME_NEXTTRACK_NEVER, + "autoresume next track", "never,all,custom", + NULL, 3, + ID2P(LANG_SET_BOOL_NO), + ID2P(LANG_ALWAYS), + ID2P(LANG_AUTORESUME_CUSTOM)), + TEXT_SETTING(0, autoresume_strpat, "autoresume next track patterns", + "podcast", NULL, NULL), #endif OFFON_SETTING(0, runtimedb, LANG_RUNTIMEDB_ACTIVE, false,