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:
committed by
Chris Cummer
parent
fa0d8761ae
commit
86b32b3f9f
27
modules/twitch/client.go
Normal file
27
modules/twitch/client.go
Normal 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)
|
||||
}
|
||||
16
modules/twitch/keyboard.go
Normal file
16
modules/twitch/keyboard.go
Normal 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")
|
||||
}
|
||||
45
modules/twitch/settings.go
Normal file
45
modules/twitch/settings.go
Normal 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
133
modules/twitch/widget.go
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user