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  }