@@ -1736,7 +1736,15 @@ class PodcastFooter extends HTMLElement {
17361736 } catch ( _ ) { }
17371737 }
17381738
1739- /** Apply saved position and resume playback if it was active. */
1739+ /** Apply saved position and resume playback if it was active.
1740+ *
1741+ * During Turbolinks navigation, the `<audio>` element survives (the footer
1742+ * is `data-turbolinks-permanent`) and keeps playing. The saved `currentTime`
1743+ * is already close to real-time because the unbounded audio advanced during
1744+ * navigation. Unconditionally seeking would cause an audible interruption
1745+ * (browser seeks the audio buffer), so we skip the seek when the correction
1746+ * is trivial (< 500 ms). Similarly, we only call `play()` if the audio is
1747+ * actually paused — calling it on an already-playing element can glitch. */
17401748 _applyPositionAndResume ( state ) {
17411749 if ( ! state ) return ;
17421750 const elapsed = ( state . timestamp != null )
@@ -1754,10 +1762,18 @@ class PodcastFooter extends HTMLElement {
17541762 this . _audio . duration || Infinity ,
17551763 ) ;
17561764 }
1757- this . _audio . currentTime = targetTime ;
1765+ // Only seek if the position differs meaningfully — the audio may have
1766+ // played through navigation uninterrupted, so currentTime is already
1767+ // accurate. An unnecessary seek causes an audible gap (issue #8).
1768+ if ( Math . abs ( targetTime - this . _audio . currentTime ) > 0.5 ) {
1769+ this . _audio . currentTime = targetTime ;
1770+ }
17581771 }
17591772
1760- if ( ! state . paused ) {
1773+ // Don't call play() if already playing — the audio likely survived
1774+ // reconnection and is still active. Calling play() on an already-playing
1775+ // element can cause an audible interruption (issue #8).
1776+ if ( ! state . paused && this . _audio . paused ) {
17611777 this . _audio . play ( ) ?. catch ( ( ) => { } ) ;
17621778 }
17631779 }
0 commit comments