fixed repeatOne/ same track twice in a row issues
This commit is contained in:
@@ -38,6 +38,7 @@ type Player struct {
|
|||||||
volume *effects.Volume
|
volume *effects.Volume
|
||||||
speakerStreamer beep.Streamer
|
speakerStreamer beep.Streamer
|
||||||
playbackFinishedHandler func()
|
playbackFinishedHandler func()
|
||||||
|
trackChangeID uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// State represents the current playback state.
|
// State represents the current playback state.
|
||||||
@@ -223,9 +224,14 @@ func (p *Player) emitTrackChanged() {
|
|||||||
speaker.Unlock()
|
speaker.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increment track change ID so the frontend can detect changes
|
||||||
|
// even when the same file plays consecutively.
|
||||||
|
p.trackChangeID++
|
||||||
|
|
||||||
// Emit comprehensive track info
|
// Emit comprehensive track info
|
||||||
trackInfo["trackLength"] = trackLengthSecs
|
trackInfo["trackLength"] = trackLengthSecs
|
||||||
trackInfo["seekPosition"] = seekPosition
|
trackInfo["seekPosition"] = seekPosition
|
||||||
|
trackInfo["trackChangeId"] = p.trackChangeID
|
||||||
runtime.EventsEmit(p.ctx, events.TrackChanged, trackInfo)
|
runtime.EventsEmit(p.ctx, events.TrackChanged, trackInfo)
|
||||||
|
|
||||||
p.logger.Info("Emitting TrackChangedEvent with track info", "trackInfo", trackInfo)
|
p.logger.Info("Emitting TrackChangedEvent with track info", "trackInfo", trackInfo)
|
||||||
|
|||||||
+19
-1
@@ -653,7 +653,8 @@ func (q *Queue) RemoveTrack(position int) {
|
|||||||
q.emitQueueChanged()
|
q.emitQueueChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next advances to the next track.
|
// Next advances to the next track. In RepeatOne mode, the current
|
||||||
|
// track is replayed instead of advancing.
|
||||||
func (q *Queue) Next() {
|
func (q *Queue) Next() {
|
||||||
q.mu.Lock()
|
q.mu.Lock()
|
||||||
defer q.mu.Unlock()
|
defer q.mu.Unlock()
|
||||||
@@ -662,6 +663,14 @@ func (q *Queue) Next() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repeat One: replay the current track.
|
||||||
|
if q.repeatMode == RepeatOne {
|
||||||
|
q.playCurrentTrack()
|
||||||
|
q.emitQueueChanged()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
nextIdx := q.nextIndex()
|
nextIdx := q.nextIndex()
|
||||||
if nextIdx == -1 {
|
if nextIdx == -1 {
|
||||||
q.onQueueExhausted()
|
q.onQueueExhausted()
|
||||||
@@ -675,6 +684,7 @@ func (q *Queue) Next() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Previous goes to the previous track (or restarts current if >3s in).
|
// Previous goes to the previous track (or restarts current if >3s in).
|
||||||
|
// In RepeatOne mode, the current track is replayed instead of navigating.
|
||||||
func (q *Queue) Previous() {
|
func (q *Queue) Previous() {
|
||||||
q.mu.Lock()
|
q.mu.Lock()
|
||||||
defer q.mu.Unlock()
|
defer q.mu.Unlock()
|
||||||
@@ -683,6 +693,14 @@ func (q *Queue) Previous() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repeat One: replay the current track.
|
||||||
|
if q.repeatMode == RepeatOne {
|
||||||
|
q.playCurrentTrack()
|
||||||
|
q.emitQueueChanged()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// If more than 3 seconds into the track, restart it.
|
// If more than 3 seconds into the track, restart it.
|
||||||
if q.player != nil {
|
if q.player != nil {
|
||||||
posSecs, err := q.player.CurrentPositionSeconds()
|
posSecs, err := q.player.CurrentPositionSeconds()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class SeekBar extends LitElement {
|
|||||||
private player = new PlayerController(this);
|
private player = new PlayerController(this);
|
||||||
private rangeRef = createRef<WaSlider>();
|
private rangeRef = createRef<WaSlider>();
|
||||||
private timerID: number = -1;
|
private timerID: number = -1;
|
||||||
private previousTrackPath: string | null = null;
|
private previousTrackChangeId: number = -1;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private seekValue: number = 0;
|
private seekValue: number = 0;
|
||||||
@@ -74,11 +74,13 @@ export class SeekBar extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override updated() {
|
override updated() {
|
||||||
// Detect track change and reset seek position
|
// Detect track change and reset seek position.
|
||||||
const currentPath = this.player.currentTrack?.filePath ?? null;
|
// Uses trackChangeId instead of filePath so the seek bar resets
|
||||||
|
// even when the same file plays consecutively in the queue.
|
||||||
|
const currentChangeId = this.player.currentTrack?.trackChangeId ?? -1;
|
||||||
|
|
||||||
if (currentPath !== this.previousTrackPath) {
|
if (currentChangeId !== this.previousTrackChangeId) {
|
||||||
this.previousTrackPath = currentPath;
|
this.previousTrackChangeId = currentChangeId;
|
||||||
this.seekValue = this.player.currentTrack?.seekPosition ?? 0;
|
this.seekValue = this.player.currentTrack?.seekPosition ?? 0;
|
||||||
this.stopProgress();
|
this.stopProgress();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface TrackInfo {
|
|||||||
album: string; // album name
|
album: string; // album name
|
||||||
coverArt: string; // URL path to cover art (e.g., "/covers/abc.jpg") or empty string
|
coverArt: string; // URL path to cover art (e.g., "/covers/abc.jpg") or empty string
|
||||||
coverArtThumbnail: string; // URL path to thumbnail (e.g., "/covers/abc_thumb.jpg") or empty string
|
coverArtThumbnail: string; // URL path to thumbnail (e.g., "/covers/abc_thumb.jpg") or empty string
|
||||||
|
trackChangeId: number; // monotonic counter to detect track changes even when the same file plays consecutively
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayerState {
|
export interface PlayerState {
|
||||||
|
|||||||
Reference in New Issue
Block a user