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"
+
+
+
+ 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)"
+
+
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,