github.com/wtfutil/wtf@v0.43.0/modules/transmission/widget.go (about)

     1  package transmission
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  
     8  	"github.com/hekmon/transmissionrpc/v2"
     9  	"github.com/rivo/tview"
    10  	"github.com/wtfutil/wtf/view"
    11  )
    12  
    13  // Widget is the container for transmission data
    14  type Widget struct {
    15  	view.ScrollableWidget
    16  
    17  	client   *transmissionrpc.Client
    18  	settings *Settings
    19  	mu       sync.Mutex
    20  	torrents []transmissionrpc.Torrent
    21  	err      error
    22  }
    23  
    24  // NewWidget creates a new instance of a widget
    25  func NewWidget(tviewApp *tview.Application, redrawChan chan bool, pages *tview.Pages, settings *Settings) *Widget {
    26  	widget := Widget{
    27  		ScrollableWidget: view.NewScrollableWidget(tviewApp, redrawChan, pages, settings.Common),
    28  
    29  		settings: settings,
    30  	}
    31  
    32  	widget.SetRenderFunction(widget.display)
    33  	widget.initializeKeyboardControls()
    34  
    35  	go buildClient(&widget)
    36  
    37  	return &widget
    38  }
    39  
    40  /* -------------------- Exported Functions -------------------- */
    41  
    42  // Fetch retrieves torrent data from the Transmission daemon
    43  func (widget *Widget) Fetch() ([]transmissionrpc.Torrent, error) {
    44  	if widget.client == nil {
    45  		return nil, errors.New("client was not initialized")
    46  	}
    47  
    48  	torrents, err := widget.client.TorrentGetAll(context.Background())
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	out := make([]transmissionrpc.Torrent, 0)
    54  	for _, torrent := range torrents {
    55  		if widget.settings.hideComplete {
    56  			if *torrent.PercentDone == 1.0 {
    57  				continue
    58  			}
    59  		}
    60  
    61  		out = append(out, torrent)
    62  	}
    63  
    64  	return out, nil
    65  }
    66  
    67  // Refresh updates the data for this widget and displays it onscreen
    68  func (widget *Widget) Refresh() {
    69  	torrents, err := widget.Fetch()
    70  	count := 0
    71  
    72  	if err == nil {
    73  		count = len(torrents)
    74  	}
    75  
    76  	widget.mu.Lock()
    77  	widget.err = err
    78  	widget.torrents = torrents
    79  	widget.SetItemCount(count)
    80  	widget.mu.Unlock()
    81  
    82  	widget.display()
    83  }
    84  
    85  // Next selects the next item in the list
    86  func (widget *Widget) Next() {
    87  	widget.ScrollableWidget.Next()
    88  }
    89  
    90  // Prev selects the previous item in the list
    91  func (widget *Widget) Prev() {
    92  	widget.ScrollableWidget.Prev()
    93  }
    94  
    95  // Unselect clears the selection of list items
    96  func (widget *Widget) Unselect() {
    97  	widget.ScrollableWidget.Unselect()
    98  	widget.RenderFunction()
    99  }
   100  
   101  /* -------------------- Unexported Functions -------------------- */
   102  
   103  // buildClient creates a persisten transmission client
   104  func buildClient(widget *Widget) {
   105  	widget.mu.Lock()
   106  	defer widget.mu.Unlock()
   107  
   108  	client, err := transmissionrpc.New(widget.settings.host, widget.settings.username, widget.settings.password,
   109  		&transmissionrpc.AdvancedConfig{
   110  			Port:   widget.settings.port,
   111  			RPCURI: widget.settings.url,
   112  			HTTPS:  widget.settings.https,
   113  		})
   114  	if err != nil {
   115  		client = nil
   116  	}
   117  
   118  	widget.client = client
   119  }
   120  
   121  func (widget *Widget) currentTorrent() *transmissionrpc.Torrent {
   122  	if len(widget.torrents) == 0 {
   123  		return nil
   124  	}
   125  
   126  	if len(widget.torrents) <= widget.Selected {
   127  		return nil
   128  	}
   129  
   130  	return &widget.torrents[widget.Selected]
   131  }
   132  
   133  // deleteSelected removes the selected torrent from transmission
   134  // This action is non-destructive, it does not delete the files on the host
   135  func (widget *Widget) deleteSelectedTorrent() {
   136  	if widget.client == nil {
   137  		return
   138  	}
   139  
   140  	currTorrent := widget.currentTorrent()
   141  	if currTorrent == nil {
   142  		return
   143  	}
   144  
   145  	ids := []int64{*currTorrent.ID}
   146  
   147  	removePayload := transmissionrpc.TorrentRemovePayload{
   148  		IDs:             ids,
   149  		DeleteLocalData: false,
   150  	}
   151  
   152  	err := widget.client.TorrentRemove(context.Background(), removePayload)
   153  	if err != nil {
   154  		return
   155  	}
   156  
   157  	widget.display()
   158  }
   159  
   160  // pauseUnpauseTorrent either pauses or unpauses the downloading and seeding of the selected torrent
   161  func (widget *Widget) pauseUnpauseTorrent() {
   162  	if widget.client == nil {
   163  		return
   164  	}
   165  
   166  	currTorrent := widget.currentTorrent()
   167  	if currTorrent == nil {
   168  		return
   169  	}
   170  
   171  	ids := []int64{*currTorrent.ID}
   172  
   173  	var err error
   174  	if *currTorrent.Status == transmissionrpc.TorrentStatusStopped {
   175  		err = widget.client.TorrentStartIDs(context.Background(), ids)
   176  	} else {
   177  		err = widget.client.TorrentStopIDs(context.Background(), ids)
   178  	}
   179  
   180  	if err != nil {
   181  		return
   182  	}
   183  
   184  	widget.display()
   185  }