1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

Adding twitch module to display top streams (#805)

This commit is contained in:
Bjoern Weidlich
2019-12-30 19:20:54 -08:00
committed by Chris Cummer
parent fa0d8761ae
commit 86b32b3f9f
9 changed files with 256 additions and 0 deletions

27
modules/twitch/client.go Normal file
View File

@@ -0,0 +1,27 @@
package twitch
import (
"fmt"
"github.com/nicklaw5/helix"
)
type Twitch struct {
client *helix.Client
}
func NewClient(clientId string) *Twitch {
client, err := helix.NewClient(&helix.Options{
ClientID: clientId,
})
if err != nil {
fmt.Println(err)
}
return &Twitch{client: client}
}
func (t *Twitch) TopStreams(params *helix.StreamsParams) (*helix.StreamsResponse, error) {
if params == nil {
params = &helix.StreamsParams{}
}
return t.client.GetStreams(params)
}

View File

@@ -0,0 +1,16 @@
package twitch
import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
widget.InitializeCommonControls(widget.Refresh)
widget.SetKeyboardChar("j", widget.Next, "Select next item")
widget.SetKeyboardChar("k", widget.Prev, "Select previous item")
widget.SetKeyboardChar("o", widget.openTwitch, "Open target URL in browser")
widget.SetKeyboardKey(tcell.KeyDown, widget.Next, "Select next item")
widget.SetKeyboardKey(tcell.KeyUp, widget.Prev, "Select previous item")
widget.SetKeyboardKey(tcell.KeyEnter, widget.openTwitch, "Open stream in browser")
widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect, "Clear selection")
}

View File

@@ -0,0 +1,45 @@
package twitch
import (
"github.com/olebedev/config"
"github.com/wtfutil/wtf/cfg"
"github.com/wtfutil/wtf/utils"
"os"
)
const (
defaultFocusable = true
)
type Settings struct {
common *cfg.Common
numberOfResults int `help:"Number of results to show. Default is 10." optional:"true"`
clientId string `help:"Client Id (default is env var TWITCH_CLIENT_ID)"`
languages []string `help:"Stream languages" optional:"true"`
gameIds []string `help:"Twitch Game IDs" optional:"true"`
streamType string `help:"Type of stream 'live' (default), 'all', 'vodcast'" optional:"true"`
userIds []string `help:"Twitch user ids" optional:"true"`
userLogins []string `help:"Twitch user names" optional:"true"`
}
func defaultLanguage() []interface{} {
var defaults []interface{}
defaults = append(defaults, "en")
return defaults
}
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
twitch := ymlConfig.UString("twitch")
settings := Settings{
common: cfg.NewCommonSettingsFromModule(name, twitch, defaultFocusable, ymlConfig, globalConfig),
numberOfResults: ymlConfig.UInt("numberOfResults", 10),
clientId: ymlConfig.UString("clientId", os.Getenv("TWITCH_CLIENT_ID")),
languages: utils.ToStrs(ymlConfig.UList("languages", defaultLanguage())),
streamType: ymlConfig.UString("streamType", "live"),
gameIds: utils.ToStrs(ymlConfig.UList("gameIds", make([]interface{}, 0))),
userIds: utils.ToStrs(ymlConfig.UList("userIds", make([]interface{}, 0))),
userLogins: utils.ToStrs(ymlConfig.UList("userLogins", make([]interface{}, 0))),
}
return &settings
}

133
modules/twitch/widget.go Normal file
View File

@@ -0,0 +1,133 @@
package twitch
import (
"errors"
"fmt"
"github.com/nicklaw5/helix"
"github.com/rivo/tview"
"github.com/wtfutil/wtf/utils"
"github.com/wtfutil/wtf/view"
)
type Widget struct {
view.KeyboardWidget
view.ScrollableWidget
settings *Settings
err error
twitch *Twitch
topStreams []*Stream
}
type Stream struct {
Streamer string
ViewerCount int
Language string
GameID string
Title string
}
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := &Widget{
KeyboardWidget: view.NewKeyboardWidget(app, pages, settings.common),
ScrollableWidget: view.NewScrollableWidget(app, settings.common),
settings: settings,
twitch: NewClient(settings.clientId),
}
widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
widget.KeyboardWidget.SetView(widget.View)
return widget
}
func (widget *Widget) Refresh() {
response, err := widget.twitch.TopStreams(&helix.StreamsParams{
First: widget.settings.numberOfResults,
GameIDs: widget.settings.gameIds,
Language: widget.settings.languages,
Type: widget.settings.streamType,
UserIDs: widget.settings.gameIds,
UserLogins: widget.settings.userLogins,
})
if err != nil {
handleError(widget, err)
} else if response.ErrorMessage != "" {
handleError(widget, errors.New(response.ErrorMessage))
} else {
streams := makeStreams(response)
widget.topStreams = streams
widget.err = nil
if len(streams) <= widget.settings.numberOfResults {
widget.SetItemCount(len(widget.topStreams))
} else {
widget.topStreams = streams[:widget.settings.numberOfResults]
widget.SetItemCount(len(widget.topStreams))
}
}
widget.Render()
}
func (widget *Widget) Render() {
widget.Redraw(widget.content)
}
func makeStreams(response *helix.StreamsResponse) []*Stream {
streams := make([]*Stream, 0)
for _, b := range response.Data.Streams {
streams = append(streams, &Stream{
b.UserName,
b.ViewerCount,
b.Language,
b.GameID,
b.Title,
})
}
return streams
}
func handleError(widget *Widget, err error) {
widget.err = err
widget.topStreams = nil
widget.SetItemCount(0)
}
func (widget *Widget) content() (string, string, bool) {
var title = "Top Streams"
if widget.CommonSettings().Title != "" {
title = widget.CommonSettings().Title
}
if widget.err != nil {
return title, widget.err.Error(), true
}
if len(widget.topStreams) == 0 {
return title, "No data", false
}
var str string
for idx, stream := range widget.topStreams {
row := fmt.Sprintf(
"[%s]%2d. [red]%s [white]%s",
widget.RowColor(idx),
idx+1,
utils.PrettyNumber(float64(stream.ViewerCount)),
stream.Streamer,
)
str += utils.HighlightableHelper(widget.View, row, idx, len(stream.Streamer))
}
return title, str, false
}
// Opens stream in the browser
func (widget *Widget) openTwitch() {
sel := widget.GetSelected()
if sel >= 0 && widget.topStreams != nil && sel < len(widget.topStreams) {
stream := widget.topStreams[sel]
fullLink := "https://twitch.com/" + stream.Streamer
utils.OpenFile(fullLink)
}
}