Add artist/track details to now playing view
This commit is contained in:
parent
8a1a41eb1f
commit
3537881a9b
7 changed files with 82 additions and 27 deletions
11
app/app.go
11
app/app.go
|
|
@ -51,7 +51,6 @@ func PlayChannel(chn *components.ChannelItem, ctx *context.AppContext) {
|
|||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if streamURL, ok := difm.GetStreamURL(body); ok {
|
||||
format := difm.Stream(streamURL, ctx)
|
||||
setCurrentChannel(chn, ctx)
|
||||
|
||||
if !ctx.SpeakerInitialized {
|
||||
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
|
||||
|
|
@ -59,13 +58,19 @@ func PlayChannel(chn *components.ChannelItem, ctx *context.AppContext) {
|
|||
|
||||
speaker.Play(ctx.AudioStream)
|
||||
ctx.IsPlaying = true
|
||||
|
||||
setNowPlaying(chn, ctx)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func setCurrentChannel(chn *components.ChannelItem, ctx *context.AppContext) {
|
||||
func setNowPlaying(chn *components.ChannelItem, ctx *context.AppContext) {
|
||||
ctx.CurrentChannel = chn
|
||||
cp := difm.GetCurrentlyPlaying(ctx)
|
||||
ctx.View.App.QueueUpdateDraw(func() {
|
||||
ctx.View.NowPlaying.SetChannel(chn)
|
||||
ctx.View.NowPlaying.Channel = chn
|
||||
track := cp.Track
|
||||
ctx.View.NowPlaying.Artist = track.DisplayArtist
|
||||
ctx.View.NowPlaying.Track = track.DisplayTitle
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package components
|
||||
|
||||
import "time"
|
||||
|
||||
// ChannelItem contains di.fm channel metadata
|
||||
type ChannelItem struct {
|
||||
ID int64 `json:"id"`
|
||||
|
|
@ -7,3 +9,17 @@ type ChannelItem struct {
|
|||
Name string `json:"name"`
|
||||
Playlist string `json:"playlist"`
|
||||
}
|
||||
|
||||
// CurrentlyPlaying contains the currently playing metadata for a di.fm channel
|
||||
type CurrentlyPlaying struct {
|
||||
ChannelID int64 `json:"channel_id"`
|
||||
ChannelKey string `json:"channel_key"`
|
||||
Track Track `json:"track"`
|
||||
}
|
||||
|
||||
type Track struct {
|
||||
DisplayArtist string `json:"display_artist"`
|
||||
DisplayTitle string `json:"display_title"`
|
||||
Duration float64 `json:"duration"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
// SaveToken persists the di.fm API token to disk
|
||||
func SaveToken(token string) {
|
||||
viper.Set("username", "")
|
||||
viper.Set("password", "")
|
||||
|
|
@ -28,6 +29,7 @@ func SaveToken(token string) {
|
|||
saveConfig()
|
||||
}
|
||||
|
||||
// GetToken returns the di.fm API token if one is available
|
||||
func GetToken() (token string) {
|
||||
return viper.GetString("token")
|
||||
}
|
||||
|
|
@ -47,10 +49,9 @@ func configFilePath() string {
|
|||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
return home
|
||||
} else {
|
||||
home = os.Getenv("HOME")
|
||||
}
|
||||
|
||||
home = os.Getenv("HOME")
|
||||
dir := fmt.Sprintf("%s/.config/dicli/", home)
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ import (
|
|||
"github.com/faiface/beep"
|
||||
)
|
||||
|
||||
func CreateAppContext() *AppContext {
|
||||
ctx := &AppContext{
|
||||
View: views.CreateAppView(),
|
||||
}
|
||||
// CreateAppContext creates the application context
|
||||
func CreateAppContext(view *views.AppView) *AppContext {
|
||||
ctx := &AppContext{View: view}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// AppContext is a shared context to be shared across the application
|
||||
type AppContext struct {
|
||||
AudioStream beep.StreamSeekCloser
|
||||
CurrentChannel *components.ChannelItem
|
||||
|
|
|
|||
14
dicli.go
14
dicli.go
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/acaloiaro/dicli/config"
|
||||
"github.com/acaloiaro/dicli/context"
|
||||
"github.com/acaloiaro/dicli/difm"
|
||||
"github.com/acaloiaro/dicli/views"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rivo/tview"
|
||||
|
|
@ -15,19 +16,8 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
/* di.fm API
|
||||
Track details: http://www.di.fm/tracks/<track id>
|
||||
Listen history: POST /_papi/v1/di/listen_history
|
||||
Payload: {track_id: 2918701, playlist_id: 63675}
|
||||
Currently playing (all stations): https://www.di.fm/_papi/v1/di/currently_playing
|
||||
Skip track: https://www.di.fm/_papi/v1/di/skip_events
|
||||
*/
|
||||
var ctx *context.AppContext
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
pflag.String("username", "", "your di.fm username")
|
||||
pflag.String("password", "", "your di.fm password")
|
||||
|
|
@ -48,7 +38,7 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx = context.CreateAppContext()
|
||||
ctx = context.CreateAppContext(views.CreateAppView())
|
||||
ctx.DifmToken = token
|
||||
|
||||
run()
|
||||
|
|
|
|||
38
difm/difm.go
38
difm/difm.go
|
|
@ -20,6 +20,15 @@ import (
|
|||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
/* di.fm API
|
||||
Track details: http://www.di.fm/tracks/<track id>
|
||||
Listen history: POST /_papi/v1/di/listen_history
|
||||
Payload: {track_id: 2918701, playlist_id: 63675}
|
||||
Currently playing (all stations): https://www.di.fm/_papi/v1/di/currently_playing
|
||||
Skip track: https://www.di.fm/_papi/v1/di/skip_events
|
||||
*/
|
||||
|
||||
// Authenticate authenticates to the di.fm API with username and password, returning the listen token
|
||||
func Authenticate(username, password string) (token string) {
|
||||
authURL := "https://api.audioaddict.com/v1/di/members/authenticate"
|
||||
client := &http.Client{}
|
||||
|
|
@ -66,6 +75,35 @@ func GetStreamURL(data []byte) (streamURL string, ok bool) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetCurrentlyPlaying fetches the list of all currently playing tracks site-side
|
||||
func GetCurrentlyPlaying(ctx *context.AppContext) (currentlyPlaying components.CurrentlyPlaying) {
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("GET", "https://www.di.fm/_papi/v1/di/currently_playing", nil)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
// TODO: Don't exit here. Once there's a status message area in the app, populate it with the error
|
||||
log.Println("unable to list channels", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var currentlyPlayingStations []components.CurrentlyPlaying
|
||||
json.Unmarshal(body, ¤tlyPlayingStations)
|
||||
|
||||
for _, cp := range currentlyPlayingStations {
|
||||
if cp.ChannelID == ctx.CurrentChannel.ID {
|
||||
return cp
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ListChannels lists all premium MP3 channels
|
||||
func ListChannels() (channels []components.ChannelItem) {
|
||||
client := &http.Client{}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,15 @@ func CreateAppView() *AppView {
|
|||
// NowPlayingView is a custom view for dispalying the currently playing channel
|
||||
type NowPlayingView struct {
|
||||
*tview.Box
|
||||
channel *components.ChannelItem
|
||||
Channel *components.ChannelItem
|
||||
Artist string
|
||||
Track string
|
||||
}
|
||||
|
||||
func newNowPlaying(chn *components.ChannelItem) *NowPlayingView {
|
||||
np := &NowPlayingView{
|
||||
Box: tview.NewBox(),
|
||||
channel: chn,
|
||||
Channel: chn,
|
||||
}
|
||||
|
||||
np.SetTitle(" Now Playing ")
|
||||
|
|
@ -45,12 +47,15 @@ func (n *NowPlayingView) Draw(screen tcell.Screen) {
|
|||
n.Box.Draw(screen)
|
||||
x, y, width, _ := n.GetInnerRect()
|
||||
|
||||
line := fmt.Sprintf(`%s[white] %s`, "Channel:", n.channel.Name)
|
||||
line := fmt.Sprintf("%s[white] %s", "Channel:", n.Channel.Name)
|
||||
tview.Print(screen, line, x, y, width, tview.AlignLeft, tcell.ColorYellow)
|
||||
}
|
||||
|
||||
func (n *NowPlayingView) SetChannel(chn *components.ChannelItem) {
|
||||
n.channel = chn
|
||||
line = fmt.Sprintf("%s[white] %s", "Artist:", n.Artist)
|
||||
tview.Print(screen, line, x, y+1, width, tview.AlignLeft, tcell.ColorYellow)
|
||||
|
||||
line = fmt.Sprintf("%s[white] %s", "Track:", n.Track)
|
||||
tview.Print(screen, line, x, y+2, width, tview.AlignLeft, tcell.ColorYellow)
|
||||
|
||||
}
|
||||
|
||||
func createChannelList() *tview.List {
|
||||
|
|
|
|||
Loading…
Reference in a new issue