fix: changing channels quickly causes two to play
This commit is contained in:
parent
8782746579
commit
36059f23ac
4 changed files with 42 additions and 11 deletions
16
app/app.go
16
app/app.go
|
|
@ -2,6 +2,7 @@ package app
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
c "context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -103,25 +104,36 @@ func Play(ctx *context.AppContext) {
|
|||
}
|
||||
|
||||
ctx.IsPlaying = true
|
||||
streamCtx, cancel := c.WithCancel(c.Background())
|
||||
ctx.StreamCancel = cancel
|
||||
|
||||
go func() {
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("GET", chn.Playlist, nil)
|
||||
req, _ := http.NewRequestWithContext(streamCtx, "GET", chn.Playlist, nil)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
if streamCtx.Err() == nil {
|
||||
ctx.SetStatusMessage(fmt.Sprintf("Unable to stream channel: %s. Try again.", chn.Name))
|
||||
}
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
if streamCtx.Err() == nil {
|
||||
ctx.SetStatusMessage(fmt.Sprintf("Unable to stream channel: %s. Try again.", chn.Name))
|
||||
}
|
||||
return
|
||||
}
|
||||
if streamURL, ok := difm.GetStreamURL(body, ctx); ok {
|
||||
select {
|
||||
case <-streamCtx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
UpdateNowPlaying(ctx, chn)
|
||||
difm.Stream(streamURL, ctx)
|
||||
difm.Stream(streamURL, ctx, streamCtx)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
c "context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
|
|
@ -40,6 +41,7 @@ type AppContext struct {
|
|||
Player *pulse.PlaybackStream
|
||||
ShowStatus bool // The status pane will be visible when true
|
||||
StatusChannel chan components.StatusMessage
|
||||
StreamCancel c.CancelFunc
|
||||
View *views.ViewContext
|
||||
}
|
||||
|
||||
|
|
|
|||
28
difm/difm.go
28
difm/difm.go
|
|
@ -219,20 +219,25 @@ func ListFavorites(ctx *context.AppContext) (favorites []components.FavoriteItem
|
|||
}
|
||||
|
||||
// Stream streams the provided URL using the given di.fm premium token
|
||||
func Stream(url string, ctx *context.AppContext) {
|
||||
func Stream(url string, ctx *context.AppContext, streamCtx c.Context) {
|
||||
client := http.DefaultClient
|
||||
u := fmt.Sprintf("%s?%s", url, config.GetToken())
|
||||
|
||||
// Keep increasing playback latency by one second for every time that the player exits with EOF
|
||||
// while ctx.IsPlaying
|
||||
for playbackLatency := 1; ctx.IsPlaying; playbackLatency++ {
|
||||
for playbackLatency := 1; ; playbackLatency++ {
|
||||
select {
|
||||
case <-streamCtx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
ctx.SetStatusMessage("Buffering stream...")
|
||||
if ctx.Player != nil {
|
||||
ctx.Player.Close()
|
||||
}
|
||||
|
||||
rctx := c.Background()
|
||||
req, err := http.NewRequestWithContext(rctx, "GET", u, nil)
|
||||
req, err := http.NewRequestWithContext(streamCtx, "GET", u, nil)
|
||||
if err != nil {
|
||||
ctx.SetStatusMessage("There was a problem streaming audio!")
|
||||
return
|
||||
|
|
@ -241,6 +246,9 @@ func Stream(url string, ctx *context.AppContext) {
|
|||
resp, err := client.Do(req)
|
||||
switch {
|
||||
case err != nil:
|
||||
if streamCtx.Err() != nil {
|
||||
return
|
||||
}
|
||||
ctx.SetStatusMessage(fmt.Sprintf("There was a problem streaming audio: %s", err.Error()))
|
||||
return
|
||||
case resp.StatusCode != 200:
|
||||
|
|
@ -254,14 +262,20 @@ func Stream(url string, ctx *context.AppContext) {
|
|||
|
||||
go func() {
|
||||
for {
|
||||
_, err = io.CopyN(audioStream, resp.Body, 512)
|
||||
if err != nil {
|
||||
_, copyErr := io.CopyN(audioStream, resp.Body, 512)
|
||||
if copyErr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(time.Duration(playbackLatency) * time.Second)
|
||||
select {
|
||||
case <-streamCtx.Done():
|
||||
resp.Body.Close()
|
||||
return
|
||||
case <-time.After(time.Duration(playbackLatency) * time.Second):
|
||||
}
|
||||
|
||||
err = player.Play(ctx, audioStream, playbackLatency)
|
||||
if err == nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ func Play(ctx *context.AppContext, stream io.ReadWriter, playbackLatency int) (e
|
|||
|
||||
func Stop(ctx *context.AppContext) {
|
||||
ctx.IsPlaying = false
|
||||
if ctx.StreamCancel != nil {
|
||||
ctx.StreamCancel()
|
||||
}
|
||||
if ctx.Player != nil {
|
||||
ctx.AudioStream.Close()
|
||||
ctx.Player.Close()
|
||||
|
|
|
|||
Loading…
Reference in a new issue