Can skip to a random track on double click
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details

This commit is contained in:
nemunaire 2024-01-14 10:17:03 +01:00
parent 677f93723b
commit 19fa419d89
7 changed files with 83 additions and 0 deletions

View File

@ -162,6 +162,21 @@ func declareInputsRoutes(cfg *config.Config, router *gin.RouterGroup) {
c.JSON(http.StatusOK, true)
})
streamRoutes.POST("/next_random_track", func(c *gin.Context) {
input, ok := c.MustGet("input").(inputs.PlaylistInput)
if !ok {
c.AbortWithStatusJSON(http.StatusMethodNotAllowed, gin.H{"errmsg": "The source doesn't support that"})
return
}
err := input.NextRandomTrack()
if err != nil {
c.AbortWithStatusJSON(http.StatusMethodNotAllowed, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, true)
})
streamRoutes.POST("/prev_track", func(c *gin.Context) {
input, ok := c.MustGet("input").(inputs.PlaylistInput)
if !ok {

View File

@ -194,6 +194,28 @@ func declareSourcesRoutes(cfg *config.Config, router *gin.RouterGroup) {
c.JSON(http.StatusOK, true)
})
sourcesRoutes.POST("/next_random_track", func(c *gin.Context) {
src := c.MustGet("source").(sources.SoundSource)
if !src.IsActive() {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"errmsg": "Source not active"})
return
}
s, ok := src.(inputs.PlaylistInput)
if !ok || !s.HasPlaylist() {
c.AbortWithStatusJSON(http.StatusMethodNotAllowed, gin.H{"errmsg": "The source doesn't support"})
return
}
err := s.NextRandomTrack()
if err != nil {
c.AbortWithStatusJSON(http.StatusMethodNotAllowed, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, true)
})
sourcesRoutes.POST("/prev_track", func(c *gin.Context) {
src := c.MustGet("source").(sources.SoundSource)

View File

@ -25,6 +25,7 @@ type ControlableInput interface {
type PlaylistInput interface {
HasPlaylist() bool
NextTrack() error
NextRandomTrack() error
PreviousTrack() error
}

View File

@ -269,6 +269,36 @@ func (s *MPVSource) NextTrack() error {
return nil
}
func (s *MPVSource) NextRandomTrack() error {
if s.ipcSocketDir == "" {
return fmt.Errorf("Not supported")
}
conn := mpvipc.NewConnection(s.ipcSocket())
err := conn.Open()
if err != nil {
return err
}
defer conn.Close()
_, err = conn.Call("playlist-shuffle")
if err != nil {
return err
}
_, err = conn.Call("playlist-next", "weak")
if err != nil {
return err
}
_, err = conn.Call("playlist-unshuffle")
if err != nil {
return err
}
return nil
}
func (s *MPVSource) PreviousTrack() error {
if s.ipcSocketDir == "" {
return fmt.Errorf("Not supported")

View File

@ -24,6 +24,7 @@
<button
class="btn btn-sm btn-primary"
on:click={() => source.nexttrack()}
on:dblclick={() => source.nextrandomtrack()}
>
<i class="bi bi-skip-forward-fill"></i>
</button>

View File

@ -39,6 +39,13 @@ export class Input {
}
}
async nextrandomtrack(idstream) {
const data = await fetch(`api/inputs/${this.id}/streams/${idstream}/next_random_track`, {headers: {'Accept': 'application/json'}, method: 'POST'});
if (data.status != 200) {
throw new Error((await res.json()).errmsg);
}
}
async prevtrack(idstream) {
const data = await fetch(`api/inputs/${this.id}/streams/${idstream}/prev_track`, {headers: {'Accept': 'application/json'}, method: 'POST'});
if (data.status != 200) {

View File

@ -46,6 +46,13 @@ export class Source {
}
}
async nextrandomtrack() {
const data = await fetch(`api/sources/${this.id}/next_random_track`, {headers: {'Accept': 'application/json'}, method: 'POST'});
if (data.status != 200) {
throw new Error((await res.json()).errmsg);
}
}
async prevtrack() {
const data = await fetch(`api/sources/${this.id}/prev_track`, {headers: {'Accept': 'application/json'}, method: 'POST'});
if (data.status != 200) {