@@ -18,7 +18,8 @@ import (
1818var torrentsWidgetTemplate = mustParseTemplate ("torrents.html" , "widget-base.html" )
1919
2020type torrentsWidget struct {
21- widgetBase `yaml:",inline"`
21+ widgetBase `yaml:",inline"`
22+
2223 URL string `yaml:"url"`
2324 AllowInsecure bool `yaml:"allow-insecure"`
2425 Username string `yaml:"username"`
@@ -27,10 +28,11 @@ type torrentsWidget struct {
2728 CollapseAfter int `yaml:"collapse-after"`
2829 Client string `yaml:"client"`
2930
31+ SortBy sortableFields [torrent ] `yaml:"sort-by"`
32+
3033 Torrents []torrent `yaml:"-"`
3134
32- // QBittorrent client
33- sessionID string // session ID for authentication
35+ sessionID string
3436}
3537
3638func (widget * torrentsWidget ) initialize () error {
@@ -65,6 +67,30 @@ func (widget *torrentsWidget) initialize() error {
6567 return fmt .Errorf ("unsupported client: %s" , widget .Client )
6668 }
6769
70+ if err := widget .SortBy .Default ("downloaded, down-speed:desc, up-speed:desc" ); err != nil {
71+ return err
72+ }
73+
74+ if err := widget .SortBy .Fields (map [string ]func (a , b torrent ) int {
75+ "name" : func (a , b torrent ) int {
76+ return strings .Compare (a .Name , b .Name )
77+ },
78+ "progress" : func (a , b torrent ) int {
79+ return numCompare (a .Progress , b .Progress )
80+ },
81+ "downloaded" : func (a , b torrent ) int {
82+ return boolCompare (a .Downloaded , b .Downloaded )
83+ },
84+ "down-speed" : func (a , b torrent ) int {
85+ return numCompare (a .DownSpeed , b .DownSpeed )
86+ },
87+ "up-speed" : func (a , b torrent ) int {
88+ return numCompare (a .UpSpeed , b .UpSpeed )
89+ },
90+ }); err != nil {
91+ return err
92+ }
93+
6894 return nil
6995}
7096
@@ -83,17 +109,7 @@ func (widget *torrentsWidget) update(ctx context.Context) {
83109 return
84110 }
85111
86- // Sort by Downloaded status first, then by Name
87- slices .SortStableFunc (torrents , func (a , b torrent ) int {
88- if a .Downloaded != b .Downloaded {
89- if ! a .Downloaded && b .Downloaded {
90- return - 1
91- }
92- return 1
93- }
94-
95- return strings .Compare (a .Name , b .Name )
96- })
112+ widget .SortBy .Apply (torrents )
97113
98114 if len (torrents ) > widget .Limit {
99115 torrents = torrents [:widget .Limit ]
@@ -110,7 +126,7 @@ const (
110126 torrentStatusDownloading = "Downloading"
111127 torrentStatusDownloaded = "Downloaded"
112128 torrentStatusSeeding = "Seeding"
113- torrentStatusStopped = "Stopped "
129+ torrentStatusPaused = "Paused "
114130 torrentStatusStalled = "Stalled"
115131 torrentStatusError = "Error"
116132 torrentStatusOther = "Other"
@@ -131,11 +147,11 @@ var qbittorrentStates = map[string][2]string{
131147 "forcedUP" : {torrentStatusSeeding , "Torrent is forced to upload, ignoring queue limit" },
132148
133149 // Stopped/Paused states
134- "stoppedDL" : {torrentStatusStopped , "Torrent is stopped" },
135- "pausedDL" : {torrentStatusStopped , "Torrent is paused and has not finished downloading" },
136- "pausedUP" : {torrentStatusStopped , "Torrent is paused and has finished downloading" },
137- "queuedDL" : {torrentStatusStopped , "Queuing is enabled and torrent is queued for download" },
138- "queuedUP" : {torrentStatusStopped , "Queuing is enabled and torrent is queued for upload" },
150+ "stoppedDL" : {torrentStatusPaused , "Torrent is stopped" },
151+ "pausedDL" : {torrentStatusPaused , "Torrent is paused and has not finished downloading" },
152+ "pausedUP" : {torrentStatusPaused , "Torrent is paused and has finished downloading" },
153+ "queuedDL" : {torrentStatusPaused , "Queuing is enabled and torrent is queued for download" },
154+ "queuedUP" : {torrentStatusPaused , "Queuing is enabled and torrent is queued for upload" },
139155
140156 // Stalled states
141157 "stalledDL" : {torrentStatusStalled , "Torrent is being downloaded, but no connections were made" },
@@ -152,14 +168,16 @@ var qbittorrentStates = map[string][2]string{
152168}
153169
154170type torrent struct {
155- Name string
156- ProgressFormatted string
157- Downloaded bool
158- Progress float64
159- State string
160- StateDescription string
161- SpeedFormatted string
162- ETAFormatted string
171+ Name string
172+ ProgressFormatted string
173+ Downloaded bool
174+ Progress float64
175+ State string
176+ StateDescription string
177+ UpSpeed uint64
178+ DownSpeed uint64
179+ DownSpeedFormatted string
180+ ETAFormatted string
163181}
164182
165183func (widget * torrentsWidget ) formatETA (seconds uint64 ) string {
@@ -231,11 +249,12 @@ func (widget *torrentsWidget) _fetchQbtTorrents() ([]torrent, bool, error) {
231249 }
232250
233251 type qbTorrent struct {
234- Name string `json:"name"`
235- Progress float64 `json:"progress"`
236- State string `json:"state"`
237- Speed uint64 `json:"dlspeed"`
238- ETA uint64 `json:"eta"` // in seconds
252+ Name string `json:"name"`
253+ Progress float64 `json:"progress"`
254+ State string `json:"state"`
255+ DownSpeed uint64 `json:"dlspeed"`
256+ UpSpeed uint64 `json:"upspeed"`
257+ ETA uint64 `json:"eta"` // in seconds
239258 }
240259
241260 var rawTorrents []qbTorrent
@@ -245,7 +264,6 @@ func (widget *torrentsWidget) _fetchQbtTorrents() ([]torrent, bool, error) {
245264
246265 torrents := make ([]torrent , len (rawTorrents ))
247266 for i , raw := range rawTorrents {
248-
249267 state := raw .State
250268 stateDescription := "Unknown state"
251269 if mappedState , exists := qbittorrentStates [raw .State ]; exists {
@@ -261,11 +279,13 @@ func (widget *torrentsWidget) _fetchQbtTorrents() ([]torrent, bool, error) {
261279 State : state ,
262280 StateDescription : stateDescription ,
263281 ETAFormatted : widget .formatETA (raw .ETA ),
282+ DownSpeed : raw .DownSpeed ,
283+ UpSpeed : raw .UpSpeed ,
264284 }
265285
266- if raw .Speed > 0 {
267- speedValue , speedUnit := formatBytes (raw .Speed )
268- torrents [i ].SpeedFormatted = fmt .Sprintf ("%s %s" , speedValue , speedUnit )
286+ if raw .DownSpeed > 0 {
287+ value , unit := formatBytes (raw .DownSpeed )
288+ torrents [i ].DownSpeedFormatted = fmt .Sprintf ("%s %s" , value , unit )
269289 }
270290 }
271291
@@ -303,7 +323,6 @@ func (widget *torrentsWidget) fetchQbtSessionID() error {
303323
304324 cookies := resp .Cookies ()
305325 if len (cookies ) == 0 {
306- fmt .Println (string (body ))
307326 return errors .New ("no session cookie received, maybe the username or password is incorrect?" )
308327 }
309328
0 commit comments