Add artist/track details to now playing view

This commit is contained in:
Adriano Caloiaro 2020-02-29 22:17:13 -05:00
parent 8a1a41eb1f
commit 3537881a9b
No known key found for this signature in database
GPG key ID: 9FFD0E7601F166AB
7 changed files with 82 additions and 27 deletions

View file

@ -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
})
}

View file

@ -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"`
}

View file

@ -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) {

View file

@ -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

View file

@ -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()

View file

@ -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, &currentlyPlayingStations)
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{}

View file

@ -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 {