You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7cacec7
Browse filesBrowse the repository at this point in the historyBrowse files
feat(audio): smarter audiobook resume when the RFID card is pulled
Two related refinements to what resume point an audiobook persists when
its card leaves the reader:
- Don't resume a barely-started book: pulling the card within the first
`minResumeSec` seconds (new General -> options setting, NVS key
`minResumeSec`, default 20 s, 0 = off) resets the resume point to the
very start instead of saving the couple of seconds played, so a
briefly-sampled card starts cleanly from the beginning next time. The
clamp lives in AudioPlayer_NvsRfidWriteWrapper and is gated to track 0
of the position-saving audiobook modes, so genuine mid-book progress is
never discarded.
- Stop-on-removal now saves the exact position: the STOP path persists
the audiobook resume point (mirroring the pause-save, skipping TTS) just
before stopSong(). So "stop instead of pause on removal" returns to the
idle animation AND continues exactly where you pulled the card on
re-apply, instead of relying on the up-to-30 s periodic checkpoint.
Web UI (new number field + load/save), en/de/fr locales (incl. an updated
stop-on-removal tooltip), the GitHub Pages demo mock and README are all
updated to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -247,7 +247,7 @@ neon logo that doubles as the SVG favicon ([`7be5254`](../../commit/7be5254)):
247
247
| Change | Commit |
248
248
| --- | --- |
249
249
| Tag removal detected via consecutive-miss counter instead of a wall-clock timeout: pause after ~0.5 s, immune to phantom dropouts and task starvation |[`1fad9cd`](../../commit/1fad9cd)|
250
-
|**Stop instead of pause when the tag is removed** (General → options, sub-option of "Pause when RFID tag is removed"): pulling the card fully stops playback (clears the playlist) rather than just pausing; re-applying the card starts it again from the beginning. Persisted in NVS (`stopRfidRem`) and applied live without a reboot |[`dd3b4d7`](../../commit/dd3b4d7)|
250
+
|**Stop instead of pause when the tag is removed** (General → options, sub-option of "Pause when RFID tag is removed"): pulling the card fully stops playback (clears the playlist, so the LEDs return to the idle animation) rather than just pausing. The audiobook resume point is now saved at the **exact** moment of removal — not just the last ~30 s periodic checkpoint — so re-applying the card continues right where you pulled it (non-position-saving content still starts over). Persisted in NVS (`stopRfidRem`) and applied live without a reboot |[`dd3b4d7`](../../commit/dd3b4d7)|
251
251
| Vendored PN5180 library with fast no-card detection: read attempts on an empty field take ~25 ms instead of ~230 ms (no more 200 ms timeout) |[`8762784`](../../commit/8762784)|
252
252
| SLIX2 password support for protected ICODE-SLIX2 tags |[`d3cc69c`](../../commit/d3cc69c)|
253
253
| Configurable idle LED and progress bar colors |[`bdc54e5`](../../commit/bdc54e5)|
@@ -261,6 +261,7 @@ neon logo that doubles as the SVG favicon ([`7be5254`](../../commit/7be5254)):
261
261
| Web-configurable OLED (new **OLED** settings tab): enable/disable the display, pick the startup animation (none / boot terminal / login splash / full), set the idle header text, toggle the battery/time/wifi/volume fields, and flip the panel 180°. Also a `CMD_TOGGLE_OLED` command for keybindings to blank the screen (e.g. at night) |[`7d86c3d`](../../commit/7d86c3d)|
262
262
| Audiobook resume fade-in: continuing a saved position briefly stutters in the first ~2 s (file open + MP3 header decode + seek-flush saturate the 1-bit SD/CPU while I2S already plays). The resume now rewinds a few seconds and fades the volume up over that span, so the glitch lands on already-heard audio — no content lost, clean sound from where you stopped. Tunable / disable via `RESUME_FADEIN_DURATION_MS` and `RESUME_FADEIN_REWIND_S` in `settings.h`|[`583225f`](../../commit/583225f)|
263
263
| Audiobooks restart from the beginning after a long pause: if a position-saving audiobook card has not been played for a configurable span (new **"Restart audiobook after (hrs)"** general setting, default 24 h, 0 = off), the next tap starts the book over instead of resuming mid-chapter — handy for kids who no longer remember where they were. The per-card last-seen timestamp lives in its own NVS namespace and is only consulted when the clock is valid (NTP/RTC) |[`445e290`](../../commit/445e290)|
264
+
| Don't resume a barely-started audiobook: if the card is pulled within the first few seconds (new **"Don't resume if pulled within (sec.)"** general setting, NVS key `minResumeSec`, default 20 s, 0 = off), the resume point is reset to the very start instead of saving the couple of seconds played — so a briefly-sampled card starts cleanly from the beginning next time rather than a few seconds in. Gated to the very first track of the position-saving audiobook modes, so genuine mid-book progress is never discarded |[`PENDING`](../../commit/PENDING)|
264
265
| **Smart forward/backward seek with press-coalescing** (`CMD_SMART_FORWARDS` / `CMD_SMART_BACKWARDS`, action codes 190/191; also track-control codes 10/11 for MQTT): on an audiobook that is a single long file these commands seek *inside* the file; on a playlist of several files they fall back to next/previous track. Rapid presses are bundled into one jump so the decoder re-syncs once instead of once per press (the old per-press seek felt sluggish on FLAC and dropped presses during the multi-second resync). A forward jump past the end of a single file **clamps to a few seconds before the end and keeps playing** instead of ending the book (`setAudioPlayTime` instead of `setTimeOffset`'s `stopSong`). The step is configurable in the web UI (General → options → **"Smart seek step (sec.)"**, NVS key `seekStep`, default 300 s = 5 min). Bind them to physical buttons in the **Buttons** settings tab. The plain `CMD_SEEK_FORWARDS`/`BACKWARDS` 30 s jump (`jumpOffset`) and the upstream next/previous-track behavior are both unchanged | [`ba3628e`](../../commit/ba3628e) |
Copy file name to clipboardExpand all lines: html/locales/de.json
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -699,12 +699,14 @@
699
699
"savePlayPosPeriodicExp": "Während ein Hörbuch läuft, wird die Position alle ~30 s im Flash gesichert. So gehen bei einem unerwarteten Stromausfall (leerer Akku, harter Aus-Schalter) nur die letzten Sekunden verloren statt bis zum Anfang des Tracks zurückzuspringen. Fork-Funktion.",
700
700
"restartFreshHrs": "Hörbuch von vorn nach (Std.)",
701
701
"restartFreshHrsExp": "Wird ein Hörbuch länger als die angegebene Stundenzahl nicht abgespielt, startet es beim nächsten Auflegen wieder von vorn statt an der gespeicherten Stelle. Praktisch für Kinder, die sich nach einem Tag Pause nicht mehr erinnern, wo sie waren. 0 = aus (immer fortsetzen). Standard: 24. Benötigt eine gültige Uhrzeit (NTP/RTC). Fork-Funktion.",
702
+
"minResumeSec": "Nicht fortsetzen bei Abziehen in (Sek.)",
703
+
"minResumeSecExp": "Wird die Karte in den ersten Sekunden eines Hörbuchs wieder abgezogen, wird der Fortsetzungspunkt auf den Anfang zurückgesetzt, statt die paar gespielten Sekunden zu speichern. Eine nur kurz angetippte Karte startet beim nächsten Mal sauber von vorn statt ein paar Sekunden mittendrin. Betrifft nur den allerersten Titel der positions-speichernden Hörbuch-Modi, echter Fortschritt mitten im Hörbuch geht also nie verloren. 0 = aus. Standard: 20. Fork-Funktion.",
702
704
"seekStep": "Smart-Spulen Schritt (Sek.)",
703
705
"seekStepExp": "Sprungweite in Sekunden für die Befehle „Smart vor/zurück\" (CMD_SMART_FORWARDS/BACKWARDS). Bei einem Hörbuch, das aus einer einzigen langen Datei besteht, spulen diese Tasten innerhalb der Datei; bei einer Playlist aus mehreren Dateien wechseln sie stattdessen den Track. Mehrere schnelle Tastendrücke werden zu einem Sprung gebündelt (nur ein Neu-Puffern statt vieler). Standard: 300 (5 Min.). Fork-Funktion.",
704
706
"pauseIfRfidRemoved": "Pause wenn RFID-Tag entfernt",
705
707
"pauseIfRfidRemovedExp": "Pausieren wenn RFID-Tag entfernt wird. Mehr Infos <a href='https://forum.espuino.de/t/welche-optionen-beim-kompilieren-gibt-es/120' target='_blank'>hier</a> unter <code>PAUSE_WHEN_RFID_REMOVED</code>.",
"stopIfRfidRemovedExp": "Wenn aktiv (nur in Kombination mit „Pause wenn RFID-Tag entfernt“): Beim Abziehen der Karte wird die Wiedergabe vollständig gestoppt statt nur pausiert. Erneutes Auflegen startet die Karte von vorn.",
709
+
"stopIfRfidRemovedExp": "Wenn aktiv (nur in Kombination mit „Pause wenn RFID-Tag entfernt“): Beim Abziehen der Karte wird die Wiedergabe vollständig gestoppt statt nur pausiert, die LEDs kehren also zur Idle-Animation zurück. Bei Hörbüchern wird die genaue Position im Moment des Abziehens gespeichert, sodass erneutes Auflegen genau dort weitermacht, wo du aufgehört hast; anderer Inhalt startet von vorn.",
708
710
"dontAcceptRfidTwice": "Denselben RFID-Tag nicht erneut akzeptieren",
709
711
"resumeOnSameRfidExp": "Wenn die Wiedergabe pausiert ist und derselbe RFID-Tag erneut aufgelegt wird, wird die Wiedergabe fortgesetzt. Funktioniert nur, wenn <em>Denselben RFID-Tag nicht erneut akzeptieren</em> aktiv ist.",
710
712
"playLastRfidOnReboot": "Letzten RFID-Tag nach Neustart abspielen",
Copy file name to clipboardExpand all lines: html/locales/en.json
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -699,12 +699,14 @@
699
699
"savePlayPosPeriodicExp": "While an audio book plays, the position is saved to flash every ~30 s. This way an unexpected power loss (dead battery, hard power-off) only loses the last few seconds instead of falling back to the start of the track. Fork feature.",
700
700
"restartFreshHrs": "Restart audiobook after (hrs)",
701
701
"restartFreshHrsExp": "If an audiobook has not been played for more than the given number of hours, it starts over from the beginning the next time the card is placed, instead of resuming the saved position. Handy for kids who, after a day's break, no longer remember where they were. 0 = off (always resume). Default: 24. Requires a valid clock (NTP/RTC). Fork feature.",
702
+
"minResumeSec": "Don't resume if pulled within (sec.)",
703
+
"minResumeSecExp": "If the card is removed within the first few seconds of an audiobook, the resume point is reset to the very beginning instead of saving the couple of seconds played. So a card that was only briefly sampled starts cleanly from the start next time rather than a few seconds in. Only affects the very first track of position-saving audiobook modes, so real mid-book progress is never discarded. 0 = off. Default: 20. Fork feature.",
702
704
"seekStep": "Smart seek step (sec.)",
703
705
"seekStepExp": "Jump distance in seconds for the \"smart forward/backward\" commands (CMD_SMART_FORWARDS/BACKWARDS). On an audiobook that is a single long file these buttons seek within the file; on a playlist of several files they change tracks instead. Several quick presses are coalesced into one jump (a single re-buffer instead of many). Default: 300 (5 min). Fork feature.",
704
706
"pauseIfRfidRemoved": "Pause when RFID tag is removed",
705
707
"pauseIfRfidRemovedExp": "Playback is paused when the RFID tag is removed. More information <a href='https://forum.espuino.de/t/welche-optionen-beim-kompilieren-gibt-es/120' target='_blank'>here</a> under <code>PAUSE_IF_RFID_REMOVED</code>.",
706
708
"stopIfRfidRemoved": "Stop instead of pause on removal",
707
-
"stopIfRfidRemovedExp": "When enabled (only together with “Pause when RFID tag is removed”): removing the tag fully stops playback instead of just pausing. Re-applying the tag starts it again from the beginning.",
709
+
"stopIfRfidRemovedExp": "When enabled (only together with “Pause when RFID tag is removed”): removing the tag fully stops playback instead of just pausing, so the LEDs return to the idle animation. For audiobooks the exact position is saved the moment the tag is removed, so re-applying it continues right where you left off; other content starts over.",
708
710
"dontAcceptRfidTwice": "Don't accept the same RFID twice",
709
711
"dontAcceptRfidTwiceExp": "RFID tags are not accepted twice in a row. Cannot be used together with <em>Pause when RFID tag is removed</em>.",
710
712
"playLastRfidOnReboot": "Play last RFID tag on restart",
Copy file name to clipboardExpand all lines: html/locales/fr.json
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -688,12 +688,14 @@
688
688
"savePlayPosPeriodicExp": "Pendant la lecture d'un livre audio, la position est enregistrée dans la mémoire flash toutes les ~30 s. Ainsi, une coupure de courant inattendue (batterie vide, arrêt brutal) ne perd que les dernières secondes au lieu de revenir au début de la piste. Fonction du fork.",
689
689
"restartFreshHrs": "Redémarrer le livre audio après (h)",
690
690
"restartFreshHrsExp": "Si un livre audio n'a pas été lu depuis plus que le nombre d'heures indiqué, il recommence depuis le début lors de la prochaine pose de la carte, au lieu de reprendre à la position enregistrée. Pratique pour les enfants qui, après une journée de pause, ne se souviennent plus où ils en étaient. 0 = désactivé (toujours reprendre). Par défaut : 24. Nécessite une horloge valide (NTP/RTC). Fonction du fork.",
691
+
"minResumeSec": "Ne pas reprendre si retirée en (s)",
692
+
"minResumeSecExp": "Si la carte est retirée pendant les premières secondes d'un livre audio, le point de reprise est remis au tout début au lieu d'enregistrer les quelques secondes lues. Une carte juste effleurée redémarre proprement depuis le début la prochaine fois, plutôt que quelques secondes plus loin. N'affecte que la toute première piste des modes livre audio qui enregistrent la position ; la vraie progression au milieu du livre n'est donc jamais perdue. 0 = désactivé. Par défaut : 20. Fonction du fork.",
691
693
"seekStep": "Pas d'avance rapide intelligente (s)",
692
694
"seekStepExp": "Distance de saut en secondes pour les commandes « avance/recul intelligent » (CMD_SMART_FORWARDS/BACKWARDS). Pour un livre audio constitué d'un seul fichier long, ces touches avancent à l'intérieur du fichier ; pour une liste de plusieurs fichiers, elles changent de piste. Plusieurs appuis rapides sont regroupés en un seul saut (une seule remise en mémoire tampon au lieu de plusieurs). Par défaut : 300 (5 min). Fonction du fork.",
693
695
"pauseIfRfidRemoved": "Mettre en pause si la balise RFID est retirée",
694
696
"pauseIfRfidRemovedExp": "Mettre en pause la lecture si la balise RFID est retirée. Plus d'informations <a href='https://forum.espuino.de/t/welche-optionen-beim-kompilieren-gibt-es/120' target='_blank'>ici</a> sous <code>PAUSE_IF_RFID_REMOVED</code>.",
695
697
"stopIfRfidRemoved": "Arrêter au lieu de mettre en pause",
696
-
"stopIfRfidRemovedExp": "Si activé (uniquement avec « Mettre en pause si la balise RFID est retirée ») : retirer la balise arrête complètement la lecture au lieu de la mettre en pause. Reposer la balise redémarre depuis le début.",
698
+
"stopIfRfidRemovedExp": "Si activé (uniquement avec « Mettre en pause si la balise RFID est retirée ») : retirer la balise arrête complètement la lecture au lieu de la mettre en pause, les LED reviennent donc à l'animation de veille. Pour les livres audio, la position exacte est enregistrée au moment du retrait, de sorte que reposer la balise reprend précisément où vous vous étiez arrêté ; les autres contenus recommencent depuis le début.",
697
699
"dontAcceptRfidTwice": "Ne pas accepter la balise RFID deux fois",
698
700
"dontAcceptRfidTwiceExp": "Ne pas accepter la même balise RFID deux fois. Ne peut pas être utilisé avec <em>Mettre en pause si la balise RFID est retirée</em>.",
699
701
"playLastRfidOnReboot": "Lire la dernière balise RFID au redémarrage",
0 commit comments