github.com/wtfutil/wtf@v0.43.0/modules/twitch/widget.go (about) 1 package twitch 2 3 import ( 4 "errors" 5 "fmt" 6 "os/exec" 7 8 helix "github.com/nicklaw5/helix/v2" 9 "github.com/rivo/tview" 10 "github.com/wtfutil/wtf/utils" 11 "github.com/wtfutil/wtf/view" 12 ) 13 14 type Widget struct { 15 view.ScrollableWidget 16 17 settings *Settings 18 err error 19 twitch *Twitch 20 topStreams []*Stream 21 } 22 23 type Stream struct { 24 Streamer string 25 ViewerCount int 26 Language string 27 GameID string 28 Title string 29 } 30 31 func NewWidget(tviewApp *tview.Application, redrawChan chan bool, pages *tview.Pages, settings *Settings) *Widget { 32 clientOpts := &ClientOpts{ 33 ClientID: settings.clientId, 34 ClientSecret: settings.clientSecret, 35 AppAccessToken: settings.appAccessToken, 36 UserAccessToken: settings.userAccessToken, 37 UserRefreshToken: settings.userRefreshToken, 38 RedirectURI: settings.redirectURI, 39 Streams: settings.streams, 40 UserID: settings.userId, 41 } 42 43 twitchClient, err := NewClient(clientOpts) 44 if err != nil { 45 fmt.Println(err) 46 } 47 48 widget := &Widget{ 49 ScrollableWidget: view.NewScrollableWidget(tviewApp, redrawChan, pages, settings.Common), 50 settings: settings, 51 twitch: twitchClient, 52 } 53 54 widget.SetRenderFunction(widget.Render) 55 widget.initializeKeyboardControls() 56 57 return widget 58 } 59 60 func (widget *Widget) Refresh() { 61 var err error 62 var response *helix.StreamsResponse 63 // Refresh the auth token on each refresh to be sure we aren't using an expired one. 64 if err = widget.twitch.RefreshOAuthToken(); err != nil { 65 handleError(widget, err) 66 } 67 68 if widget.twitch.Streams == "followed" { 69 response, err = widget.twitch.FollowedStreams(&helix.FollowedStreamsParams{ 70 UserID: widget.twitch.UserID, 71 }) 72 } else if widget.twitch.Streams == "top" { 73 response, err = widget.twitch.TopStreams(&helix.StreamsParams{ 74 First: widget.settings.numberOfResults, 75 GameIDs: widget.settings.gameIds, 76 Language: widget.settings.languages, 77 Type: widget.settings.streamType, 78 UserIDs: widget.settings.userIds, 79 UserLogins: widget.settings.userLogins, 80 }) 81 } 82 83 if err != nil { 84 handleError(widget, err) 85 } else if response.ErrorMessage != "" { 86 handleError(widget, errors.New(response.ErrorMessage)) 87 } else { 88 streams := makeStreams(response) 89 widget.topStreams = streams 90 widget.err = nil 91 if len(streams) <= widget.settings.numberOfResults { 92 widget.SetItemCount(len(widget.topStreams)) 93 } else { 94 widget.topStreams = streams[:widget.settings.numberOfResults] 95 widget.SetItemCount(len(widget.topStreams)) 96 } 97 } 98 99 widget.Render() 100 } 101 102 func (widget *Widget) Render() { 103 widget.Redraw(widget.content) 104 } 105 106 func makeStreams(response *helix.StreamsResponse) []*Stream { 107 streams := make([]*Stream, len(response.Data.Streams)) 108 for i, b := range response.Data.Streams { 109 streams[i] = &Stream{ 110 b.UserName, 111 b.ViewerCount, 112 b.Language, 113 b.GameID, 114 b.Title, 115 } 116 } 117 return streams 118 } 119 120 func handleError(widget *Widget, err error) { 121 widget.err = err 122 widget.topStreams = nil 123 widget.SetItemCount(0) 124 } 125 126 func (widget *Widget) content() (string, string, bool) { 127 var title = "Twitch Streams" 128 if widget.CommonSettings().Title != "" { 129 title = widget.CommonSettings().Title 130 } 131 if widget.err != nil { 132 return title, widget.err.Error(), true 133 } 134 if len(widget.topStreams) == 0 { 135 return title, "No data", false 136 } 137 var str string 138 139 locPrinter, _ := widget.settings.LocalizedPrinter() 140 141 for idx, stream := range widget.topStreams { 142 row := fmt.Sprintf( 143 "[%s]%2d. [red]%s [white]%s - %s", 144 widget.RowColor(idx), 145 idx+1, 146 utils.PrettyNumber(locPrinter, float64(stream.ViewerCount)), 147 stream.Streamer, 148 stream.Title, 149 ) 150 str += utils.HighlightableHelper(widget.View, row, idx, len(stream.Streamer)) 151 } 152 153 return title, str, false 154 } 155 156 // Opens stream in the browser 157 func (widget *Widget) openTwitch() { 158 sel := widget.GetSelected() 159 if sel >= 0 && widget.topStreams != nil && sel < len(widget.topStreams) { 160 stream := widget.topStreams[sel] 161 fullLink := "https://twitch.com/" + stream.Streamer 162 utils.OpenFile(fullLink) 163 } 164 } 165 166 func (widget *Widget) openStreamlink() { 167 sel := widget.GetSelected() 168 if sel >= 0 && widget.topStreams != nil && sel < len(widget.topStreams) { 169 stream := widget.topStreams[sel] 170 fullLink := "https://twitch.tv/" + stream.Streamer 171 cmd := exec.Command("streamlink", fullLink, "best") 172 err := cmd.Start() 173 if err != nil { 174 handleError(widget, err) 175 } 176 } 177 }