[PATCH 4/4] Remember resume offset for all files (or a configurable
subset) in the database.
---
apps/cuesheet.c | 14 +++-
apps/gui/wps.c | 8 ++-
apps/lang/english.lang | 182 ++++++++++++++++++++++++++++++++++++++++++++
apps/menus/settings_menu.c | 45 +++++++++++-
apps/metadata.c | 64 +++++++++++++++
apps/metadata.h | 8 ++
apps/playback.c | 46 ++++++++++-
apps/settings.h | 12 +++
apps/settings_list.c | 50 ++++++++++++
apps/tagcache.c | 10 ++-
apps/tagcache.h | 5 +-
apps/tagtree.c | 86 +++++++++++++++-----
12 files changed, 495 insertions(+), 35 deletions(-)
diff --git a/apps/cuesheet.c b/apps/cuesheet.c
index a6831fa..814c814 100644
--- a/apps/cuesheet.c
+++ b/apps/cuesheet.c
@@ -319,7 +319,14 @@ bool display_cuesheet_content(char* filename)
bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_pos)
{
int track = cue_find_current_track(cue, curr_pos);
-
+ bool prevent_skipback = false;
+
+#ifdef HAVE_TAGCACHE
+ /* Protect resume position by disallowing skipback to 00:00 of
+ current track? */
+ prevent_skipback = disallow_skipback(audio_current_track());
+#endif
+
if (direction >= 0 && track == cue->track_count - 1)
{
/* we want to get out of the cuesheet */
@@ -334,8 +341,9 @@ bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_
to previous cuesheet segment. If skipping backward after
DEFAULT_SKIP_TRESH seconds have elapsed, skip to the start of the
current cuesheet segment */
- if (direction == 1 ||
- ((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_TRESH))
+ if (direction == 1
+ || ((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_TRESH)
+ || prevent_skipback)
{
track += direction;
}
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index 7d633ad..abfd366 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -465,7 +465,13 @@ static void change_dir(int direction)
static void prev_track(unsigned long skip_thresh)
{
struct wps_state *state = skin_get_global_state();
- if (state->id3->elapsed < skip_thresh)
+ bool prevent_skipback = false;
+
+#ifdef HAVE_TAGCACHE
+ prevent_skipback = disallow_skipback(state->id3);
+#endif
+
+ if (state->id3->elapsed < skip_thresh || prevent_skipback)
{
audio_prev();
return;
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index a131096..d74b892 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -12661,3 +12661,185 @@
radio: "Signal strength:"
+
+ id: LANG_AUTORESUME
+ desc: resume settings menu
+ user: core
+
+ *: "Automatic resume"
+
+
+ *: "Automatic resume"
+
+
+ *: "Automatic resume"
+
+
+
+ id: LANG_AUTORESUME_ENABLE
+ desc: resume settings menu
+ user: core
+
+ *: "Enable automatic resume"
+
+
+ *: "Enable automatic resume"
+
+
+ *: "Enable automatic resume"
+
+
+
+ id: LANG_AUTORESUME_ENABLE_YES
+ desc: resume settings menu
+ user: core
+
+ *: "Yes (requires initialized database)"
+
+
+ *: "Yes (requires initialized database)"
+
+
+ *: "Yes (requires initialized database)"
+
+
+
+ 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_ALL_RESUMABLE
+ desc: autoresume: all resumable tracks
+ user: core
+
+ *: "All resumable tracks"
+
+
+ *: "All resumable tracks"
+
+
+ *: "All resumable tracks"
+
+
+
+ id: LANG_AUTORESUME_SKIPBACK
+ desc: Skipback settings menu to enable/disable resume
+ user: core
+
+ *: "Allow skip back to intro"
+
+
+ *: "Allow skip back to intro"
+
+
+ *: "Allow skip back to intro"
+
+
+
+ id: LANG_AUTORESUME_SKIPBACK_ALWAYS
+ desc: Skipback settings menu to enable/disable resume
+ user: core
+
+ *: "Always (Looses resume position)"
+
+
+ *: "Always (Looses resume position)"
+
+
+ *: "Always. Looses resume position"
+
+
+
+ id: LANG_AUTORESUME_SKIPBACK_NONRESUME
+ desc: Skipback settings menu to enable/disable resume
+ user: core
+
+ *: "Non-resumable tracks only"
+
+
+ *: "Non-resumable tracks only"
+
+
+ *: "Non-resumable tracks only"
+
+
+
+ id: LANG_AUTORESUME_CUSTOM_MENU
+ desc: custom resume filter menu
+ user: core
+
+ *: "Resumable tracks"
+
+
+ *: "Resumable tracks"
+
+
+ *: "Resumable tracks"
+
+
+
+ id: LANG_AUTORESUME_CUSTOM
+ desc: enable custom resume filter (based on filename/genre tag)?
+ user: core
+
+ *: "Enable customization"
+
+
+ *: "Enable customization"
+
+
+ *: "Enable customization"
+
+
+
+ id: LANG_AUTORESUME_CUSTOM_NO
+ desc: enable custom resume filter (based on filename/genre tag)?
+ user: core
+
+ *: "No (resume all tracks)"
+
+
+ *: "No (resume all tracks)"
+
+
+ *: "No (resume all tracks)"
+
+
+
+ id: LANG_AUTORESUME_PATHSUB
+ desc: custom resume filter: filename
+ user: core
+
+ *: "Path substrings (comma-separated)"
+
+
+ *: "Path substrings (comma-separated)"
+
+
+ *: "Path substrings (comma-separated)"
+
+
+
+ id: LANG_AUTORESUME_TAGSUB
+ desc: custom resume filter: genre tag
+ user: core
+
+ *: "Genre tag substrings (comma-separated)"
+
+
+ *: "Genre tag substrings (comma-separated)"
+
+
+ *: "Genre tag substrings (comma-separated)"
+
+
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 5de3a30..5bb3191 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,44 @@ MAKE_MENU(bookmark_settings_menu, ID2P(LANG_BOOKMARK_SETTINGS), 0,
/***********************************/
/***********************************/
+/* AUTORESUME MENU */
+#ifdef HAVE_TAGCACHE
+
+static void edit_name_buf(char *textbuf)
+{
+ kbd_input (textbuf, MAX_PATHNAME+1);
+}
+
+MENUITEM_SETTING(autoresume_enable, &global_settings.autoresume_enable, NULL);
+MENUITEM_SETTING(autoresume_automatic, &global_settings.autoresume_automatic,
+ NULL);
+MENUITEM_SETTING(autoresume_skipback, &global_settings.autoresume_skipback,
+ NULL);
+
+MENUITEM_SETTING(autoresume_custom, &global_settings.autoresume_custom, NULL);
+MENUITEM_FUNCTION(autoresume_pathsub, MENU_FUNC_USEPARAM,
+ ID2P(LANG_AUTORESUME_PATHSUB),
+ edit_name_buf, &global_settings.autoresume_pathsub, NULL,
+ Icon_NOICON);
+MENUITEM_FUNCTION(autoresume_tagsub, MENU_FUNC_USEPARAM,
+ ID2P(LANG_AUTORESUME_TAGSUB),
+ edit_name_buf, &global_settings.autoresume_tagsub, NULL,
+ Icon_NOICON);
+
+MAKE_MENU(autoresume_custom_menu, ID2P(LANG_AUTORESUME_CUSTOM_MENU),
+ 0, Icon_NOICON,
+ &autoresume_custom, &autoresume_pathsub, &autoresume_tagsub);
+
+MAKE_MENU(autoresume_menu, ID2P(LANG_AUTORESUME),
+ 0, Icon_NOICON,
+ &autoresume_enable, &autoresume_custom_menu, &autoresume_automatic,
+ &autoresume_skipback);
+
+#endif /* HAVE_TAGCACHE */
+/* AUTORESUME MENU */
+/***********************************/
+
+/***********************************/
/* VOICE MENU */
static int talk_callback(int action,const struct menu_item_ex *this_item);
MENUITEM_SETTING(talk_menu_item, &global_settings.talk_menu, NULL);
@@ -436,7 +475,11 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0,
&tagcache_menu,
#endif
&display_menu, &system_menu,
- &bookmark_settings_menu, &browse_langs, &voice_settings_menu,
+ &bookmark_settings_menu,
+#ifdef HAVE_TAGCACHE
+ &autoresume_menu,
+#endif
+ &browse_langs, &voice_settings_menu,
#ifdef HAVE_HOTKEY
&hotkey_menu,
#endif
diff --git a/apps/metadata.c b/apps/metadata.c
index 866e035..8f952e6 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"
@@ -405,3 +406,66 @@ void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
memcpy(dest, orig, sizeof(struct mp3entry));
adjust_mp3entry(dest, dest, orig);
}
+
+#ifdef HAVE_TAGCACHE
+
+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;
+
+ if (! global_settings.autoresume_custom)
+ goto out;
+
+ strcpy(search, global_settings.autoresume_pathsub);
+
+ for (substr = strtok_r(search, ",", &saveptr);
+ substr;
+ substr = strtok_r(NULL, ",", &saveptr))
+ {
+ if (id3->path && strcasestr(id3->path, substr))
+ goto out;
+ }
+
+ strcpy(search, global_settings.autoresume_tagsub);
+
+ for (substr = strtok_r(search, ",", &saveptr);
+ substr;
+ substr = strtok_r(NULL, ",", &saveptr))
+ {
+ 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;
+}
+
+bool disallow_skipback(struct mp3entry *id3)
+{
+ return global_settings.autoresume_enable
+ && global_settings.autoresume_skipback != AUTORESUME_SKIPBACK_ALWAYS
+ && (global_settings.autoresume_skipback == AUTORESUME_SKIPBACK_NEVER
+ || autoresumable(id3));
+}
+
+#endif /* HAVE_TAGCACHE */
diff --git a/apps/metadata.h b/apps/metadata.h
index 8c7188d..d4f5cd3 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -247,6 +247,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;
@@ -279,10 +281,16 @@ 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);
+bool disallow_skipback(struct mp3entry *id3);
+#endif
+
#endif
diff --git a/apps/playback.c b/apps/playback.c
index b18ba14..51b5ec5 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -992,13 +992,33 @@ long audio_filebufused(void)
/* Update track info after successful a codec track change */
static void audio_update_trackinfo(void)
{
+ bool resume = false;
+
/* Load the curent track's metadata into curtrack_id3 */
if (CUR_TI->id3_hid >= 0)
copy_mp3entry(thistrack_id3, bufgetid3(CUR_TI->id3_hid));
/* Reset current position */
thistrack_id3->elapsed = 0;
- thistrack_id3->offset = 0;
+
+#ifdef HAVE_TAGCACHE
+ /* 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 >= 0 /* Not never resume? */
+ && autoresumable(thistrack_id3) /* Pass Resume filter? */
+ && (global_settings.autoresume_automatic == 0 /* Always resume? */
+ || thistrack_id3->length /* Long track? */
+ >= global_settings.autoresume_automatic * 60UL * 1000UL)));
+#endif
+
+ if (!resume)
+ {
+ thistrack_id3->offset = 0;
+ }
+
+ logf("audio_update_trackinfo: Set offset for %s to %lX\n",
+ thistrack_id3->title, thistrack_id3->offset);
/* Update the codec API */
ci.filesize = CUR_TI->filesize;
@@ -1210,6 +1230,9 @@ static bool audio_load_track(size_t offset, bool start_play)
{
copy_mp3entry(thistrack_id3, id3);
thistrack_id3->offset = offset;
+ logf("audio_load_track: set offset for %s to %lX\n",
+ thistrack_id3->title,
+ offset);
}
else
memset(thistrack_id3, 0, sizeof(struct mp3entry));
@@ -1415,8 +1438,14 @@ static void audio_finish_load_track(void)
return;
}
- /* All required data is now available for the codec. */
- tracks[track_widx].taginfo_ready = true;
+ /* All required data is now available for the codec -- unless the
+ autoresume feature is in effect. In the latter case, the codec
+ must wait until after PLAYBACK_EVENT_TRACK_BUFFER, which may
+ generate a resume position. */
+#ifdef HAVE_TAGCACHE
+ if (! global_settings.autoresume_enable)
+#endif
+ tracks[track_widx].taginfo_ready = true;
if (start_play)
{
@@ -1424,10 +1453,17 @@ static void audio_finish_load_track(void)
buf_request_buffer_handle(tracks[track_widx].audio_hid);
}
- track_widx = (track_widx + 1) & MAX_TRACK_MASK;
-
send_event(PLAYBACK_EVENT_TRACK_BUFFER, track_id3);
+#ifdef HAVE_TAGCACHE
+ /* In case the autoresume feature has been enabled, finally all
+ required data is available for the codec. */
+ if (global_settings.autoresume_enable)
+ tracks[track_widx].taginfo_ready = true;
+#endif
+
+ track_widx = (track_widx + 1) & MAX_TRACK_MASK;
+
/* load next track */
LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
diff --git a/apps/settings.h b/apps/settings.h
index cd06dae..b0175b7 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_SKIPBACK_ALWAYS = 0, AUTORESUME_SKIPBACK_NONRESUME,
+ AUTORESUME_SKIPBACK_NEVER };
+
/* Alarm settings */
#ifdef HAVE_RTC_ALARM
enum { ALARM_START_WPS = 0,
@@ -576,6 +580,14 @@ struct user_settings
bool tagcache_ram; /* load tagcache to ram? */
#endif
bool tagcache_autoupdate; /* automatically keep tagcache in sync? */
+ bool autoresume_enable; /* enable autoupdate feature? */
+ int autoresume_automatic; /* resume next track? -1=never,
+ 0=always, other = if longer than .. min */
+ int autoresume_skipback; /* skipback for resumable tracks? 0=do skip back,
+ 1=only for nonresumable tracks, 2=always */
+ bool autoresume_custom; /* resume only for files matching file/tag below? */
+ unsigned char autoresume_pathsub[MAX_PATHNAME+1]; /* comma-separated list */
+ unsigned char autoresume_tagsub[MAX_PATHNAME+1]; /* dito */
bool runtimedb; /* runtime database active? */
#endif /* HAVE_TAGCACHE */
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 2922bcd..91729c8 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -332,6 +332,33 @@ static int32_t getlang_unit_0_is_skip_track(int value, int unit)
return TALK_ID(value, UNIT_SEC);
}
+#ifdef HAVE_TAGCACHE
+static const char* formatter_autoresume_automatic(char *buffer,
+ size_t buffer_size,
+ int val, const char *unit)
+{
+ (void)unit;
+ if (val == -1)
+ return str(LANG_NEVER);
+ else if (val == 0)
+ return str(LANG_AUTORESUME_ALL_RESUMABLE);
+ else
+ snprintf(buffer, buffer_size, "%d min", val);
+ return buffer;
+}
+
+static int32_t getlang_autoresume_automatic(int value, int unit)
+{
+ (void)unit;
+ if (value == -1)
+ return LANG_NEVER;
+ else if (value == 0)
+ return LANG_AUTORESUME_ALL_RESUMABLE;
+ else
+ return TALK_ID(value, UNIT_MIN);
+}
+#endif
+
#ifdef HAVE_BACKLIGHT
#ifdef SIMULATOR
#define DEFAULT_BACKLIGHT_TIMEOUT 0
@@ -1257,6 +1284,29 @@ const struct settings_list settings[] = {
ID2P(LANG_RANDOM)),
#ifdef HAVE_TAGCACHE
+ BOOL_SETTING(0, autoresume_enable, LANG_AUTORESUME_ENABLE, false,
+ "autoresume enable", off_on,
+ LANG_AUTORESUME_ENABLE_YES, LANG_SET_BOOL_NO, NULL),
+ TABLE_SETTING(F_ALLOW_ARBITRARY_VALS, autoresume_automatic,
+ LANG_AUTORESUME_AUTOMATIC, 0, "autoresume next track",
+ "never,all,5m,10m,15m,20m,25m,30m",
+ UNIT_MIN, formatter_autoresume_automatic,
+ getlang_autoresume_automatic, NULL,
+ 8, -1,0,5,10,15,20,25,30),
+ CHOICE_SETTING(0, autoresume_skipback, LANG_AUTORESUME_SKIPBACK,
+ AUTORESUME_SKIPBACK_NONRESUME,
+ "autoresume skipback", "always,nonresumable,never", NULL, 3,
+ ID2P(LANG_AUTORESUME_SKIPBACK_ALWAYS),
+ ID2P(LANG_AUTORESUME_SKIPBACK_NONRESUME),
+ ID2P(LANG_NEVER)),
+ BOOL_SETTING(0, autoresume_custom, LANG_AUTORESUME_CUSTOM, false,
+ "autoresume custom filter", off_on,
+ LANG_SET_BOOL_YES, LANG_AUTORESUME_CUSTOM_NO, NULL),
+ TEXT_SETTING(0, autoresume_pathsub, "autoresume path substring",
+ "podcast,audiobook", NULL, NULL),
+ TEXT_SETTING(0, autoresume_tagsub, "autoresume tag substring",
+ "podcast,audiobook", NULL, NULL),
+
OFFON_SETTING(0, runtimedb, LANG_RUNTIMEDB_ACTIVE, false,
"gather runtime data", NULL),
#endif
diff --git a/apps/tagcache.c b/apps/tagcache.c
index bd9e5b8..ff17897 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -191,7 +191,7 @@ static const char *tagfile_entry_ec = "ll";
/**
Note: This should be (1 + TAG_COUNT) amount of l's.
*/
-static const char *index_entry_ec = "lllllllllllllllllllll";
+static const char *index_entry_ec = "llllllllllllllllllllll";
static const char *tagcache_header_ec = "lll";
static const char *master_header_ec = "llllll";
@@ -1703,6 +1703,13 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
if (id3->bitrate == 0)
id3->bitrate = 1;
+ if (global_settings.autoresume_enable)
+ {
+ id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id);
+ logf("tagcache_fill_tags: Set offset for %s to %lX\n",
+ id3->title, id3->offset);
+ }
+
return true;
}
#endif
@@ -2323,6 +2330,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
tmpdb_copy_tag(tag_playtime);
tmpdb_copy_tag(tag_lastplayed);
tmpdb_copy_tag(tag_commitid);
+ tmpdb_copy_tag(tag_lastoffset);
/* Avoid processing this entry again. */
idx.flag |= FLAG_RESURRECTED;
diff --git a/apps/tagcache.h b/apps/tagcache.h
index b52da76..4fffcca 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -32,7 +32,7 @@
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating,
- tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
+ tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastoffset,
/* Real tags end here, count them. */
TAG_COUNT,
/* Virtual tags */
@@ -50,7 +50,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define IDX_BUF_DEPTH 64
/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
-#define TAGCACHE_MAGIC 0x5443480d
+#define TAGCACHE_MAGIC 0x5443480e
/* How much to allocate extra space for ramcache. */
#define TAGCACHE_RESERVE 32768
@@ -103,6 +103,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
(1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \
(1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \
(1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \
+ (1LU << tag_lastoffset) | \
(1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \
(1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \
(1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore))
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 75caab0..50dcbce 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -53,6 +53,8 @@
#include "storage.h"
#include "dir.h"
+#define str_or_empty(x) (x ? x : "(NULL)")
+
#define FILE_SEARCH_INSTRUCTIONS ROCKBOX_DIR "/tagnavi.config"
static int tagtree_play_folder(struct tree_context* c);
@@ -168,6 +170,8 @@ static int current_entry_count;
static struct tree_context *tc;
+extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */
+
static int get_token_str(char *buf, int size)
{
/* Find the start. */
@@ -239,6 +243,7 @@ static int get_tag(int *tag)
MATCH(tag, buf, "playcount", tag_playcount);
MATCH(tag, buf, "rating", tag_rating);
MATCH(tag, buf, "lastplayed", tag_lastplayed);
+ MATCH(tag, buf, "lastoffset", tag_lastoffset);
MATCH(tag, buf, "commitid", tag_commitid);
MATCH(tag, buf, "entryage", tag_virt_entryage);
MATCH(tag, buf, "autoscore", tag_virt_autoscore);
@@ -647,7 +652,7 @@ static void tagtree_buffer_event(void *data)
struct mp3entry *id3 = (struct mp3entry*)data;
/* Do not gather data unless proper setting has been enabled. */
- if (!global_settings.runtimedb)
+ if (!global_settings.runtimedb && !global_settings.autoresume_enable)
return;
logf("be:%s", id3->path);
@@ -661,12 +666,30 @@ static void tagtree_buffer_event(void *data)
return;
}
- id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
- if (!id3->rating)
- id3->rating = tagcache_get_numeric(&tcs, tag_rating);
- id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
- id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10;
- id3->playtime = tagcache_get_numeric(&tcs, tag_playtime);
+ if (global_settings.runtimedb)
+ {
+ id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
+ if (!id3->rating)
+ id3->rating = tagcache_get_numeric(&tcs, tag_rating);
+ id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
+ id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10;
+ id3->playtime = tagcache_get_numeric(&tcs, tag_playtime);
+
+ logf("-> %ld/%ld", id3->playcount, id3->playtime);
+ }
+
+ if (global_settings.autoresume_enable)
+ {
+ /* Load current file resume offset if not already defined (by
+ another resume mechanism) */
+ if (id3->offset == 0)
+ {
+ id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset);
+
+ logf("tagtree_buffer_event: Set offset for %s to %lX\n",
+ str_or_empty(id3->title), id3->offset);
+ }
+ }
/* Store our tagcache index pointer. */
id3->tagcache_idx = tcs.idx_id+1;
@@ -676,16 +699,14 @@ static void tagtree_buffer_event(void *data)
static void tagtree_track_finish_event(void *data)
{
- long playcount;
- long playtime;
long lastplayed;
long tagcache_idx;
struct mp3entry *id3 = (struct mp3entry*)data;
/* Do not gather data unless proper setting has been enabled. */
- if (!global_settings.runtimedb)
+ if (!global_settings.runtimedb && !global_settings.autoresume_enable)
{
- logf("runtimedb gathering not enabled");
+ logf("runtimedb gathering and autoresume not enabled");
return;
}
@@ -704,7 +725,6 @@ static void tagtree_track_finish_event(void *data)
return;
}
- playcount = id3->playcount + 1;
lastplayed = tagcache_increase_serial();
if (lastplayed < 0)
{
@@ -712,17 +732,39 @@ static void tagtree_track_finish_event(void *data)
return;
}
- /* Ignore the last 15s (crossfade etc.) */
- playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000);
-
- logf("ube:%s", id3->path);
- logf("-> %ld/%ld", playcount, playtime);
- logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000));
+ if (global_settings.runtimedb)
+ {
+ long playcount;
+ long playtime;
+
+ playcount = id3->playcount + 1;
+
+ /* Ignore the last 15s (crossfade etc.) */
+ playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000);
+
+ logf("ube:%s", id3->path);
+ logf("-> %ld/%ld", playcount, playtime);
+ logf("-> %ld/%ld/%ld", id3->elapsed, id3->length,
+ MIN(id3->length, id3->elapsed + 15 * 1000));
- /* Queue the updates to the tagcache system. */
- tagcache_update_numeric(tagcache_idx, tag_playcount, playcount);
- tagcache_update_numeric(tagcache_idx, tag_playtime, playtime);
- tagcache_update_numeric(tagcache_idx, tag_lastplayed, lastplayed);
+ /* Queue the updates to the tagcache system. */
+ tagcache_update_numeric(tagcache_idx, tag_playcount, playcount);
+ tagcache_update_numeric(tagcache_idx, tag_playtime, playtime);
+ tagcache_update_numeric(tagcache_idx, tag_lastplayed, lastplayed);
+ }
+
+ if (global_settings.autoresume_enable
+ /* do not update resume info when manually skipping across a track */
+ && (automatic_skip || (id3->elapsed >= 15UL * 1000UL)))
+ {
+ unsigned long offset
+ = automatic_skip || !autoresumable(id3) ? 0 : id3->offset;
+
+ tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);
+
+ logf("tagtree_track_finish_event: Save offset for %s: %lX",
+ str_or_empty(id3->title), offset);
+ }
}
bool tagtree_export(void)
--
1.7.1