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 }