25
25
License
26
26
-------
27
27
28
- Copyright 2018-2021 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
28
+ Copyright 2018-2025 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
29
29
Free for any use provided that patches are submitted back to me.
30
30
31
31
CHANGELOG
32
32
---------
33
33
34
+ 2025-01-28 Jason Antman <jason@jasonantman.com>:
35
+ - Update to use transmission-rpc 7.0.11 for python3.13 compatibility
36
+
34
37
2021-08-25 Jason Antman <jason@jasonantman.com>:
35
38
- Require Python >= 3.6 for f-strings and humanize package
36
39
- Add support for identifying stalled torrents and removing them
@@ -89,7 +92,7 @@ def run(
89
92
logger .info ('Found %d active torrent(s)...' , len (torrents ))
90
93
for t in torrents :
91
94
self ._set_file_priority (t , batch )
92
- if reannounce and t ._fields ['peersConnected' ]. value < 1 :
95
+ if reannounce and t .fields ['peersConnected' ] < 1 :
93
96
logger .debug (
94
97
'Reannounce (ask for more peers) torrent %s (%s)' ,
95
98
t .id , t .name
@@ -110,32 +113,28 @@ def run(
110
113
)
111
114
112
115
def _set_file_priority (self , torrent , batch ):
113
- t_id = torrent ._fields ['id' ]. value
116
+ t_id = torrent .fields ['id' ]
114
117
logger .info (
115
118
'Checking files in torrent %d (%s)' , t_id ,
116
- torrent ._get_name_string ()
119
+ torrent .name
117
120
)
118
- files = {
119
- x [0 ]: x [1 ] for x in enumerate (
120
- self ._client .get_files (ids = [t_id ])[t_id ]
121
- )
122
- }
121
+ files = torrent .get_files ()
123
122
logger .debug ('Torrent has %d files: %s' , len (files ), files )
124
123
incomplete = []
125
- for _id in sorted (files . keys () , key = lambda x : files [ x ] .name ):
126
- if files [ _id ] .size == 0 :
127
- logger .debug ('File %s has zero size' , files [ _id ] .name )
128
- incomplete .append (_id )
124
+ for file in sorted (files , key = lambda x : x .name ):
125
+ if file .size == 0 :
126
+ logger .debug ('File %s has zero size' , file .name )
127
+ incomplete .append (file . id )
129
128
continue
130
- pct = (files [ _id ] .completed / files [ _id ] .size ) * 100
129
+ pct = (file .completed / file .size ) * 100
131
130
logger .debug (
132
- 'File %d: %s - %.2f%% complete - %s, priority %s' , _id ,
133
- files [ _id ] .name , pct ,
134
- 'selected' if files [ _id ] .selected else 'unselected' ,
135
- files [ _id ] .priority
131
+ 'File %d: %s - %.2f%% complete - %s, priority %s' , file . id ,
132
+ file .name , pct ,
133
+ 'selected' if file .selected else 'unselected' ,
134
+ file .priority
136
135
)
137
136
if pct < 100 :
138
- incomplete .append (_id )
137
+ incomplete .append (file . id )
139
138
logger .debug ('%d files in torrent are incomplete' , len (incomplete ))
140
139
if len (incomplete ) > batch :
141
140
selected = incomplete [:batch ]
@@ -179,7 +178,7 @@ def _find_stalled_downloads(self, stalled_days=7, prune_stalled_pct=25):
179
178
'Torrent %s (%s) - %s, %.2f%% complete; eta=%s '
180
179
'rateUp=%s rateDown=%s; added=%s started=%s '
181
180
'active=%s done=%s' ,
182
- t ._fields ['id' ]. value , t ._get_name_string () ,
181
+ t .fields ['id' ], t .name ,
183
182
t .status , t .progress , eta , t .rateUpload ,
184
183
t .rateDownload , t .date_added , t .date_started , t .date_active ,
185
184
t .date_done
@@ -188,8 +187,8 @@ def _find_stalled_downloads(self, stalled_days=7, prune_stalled_pct=25):
188
187
if t .date_active .year > 1971 :
189
188
active = naturaldelta (now - t .date_active ) + ' ago'
190
189
print (
191
- f'STALLED: Torrent { t ._fields ["id" ]. value } '
192
- f'({ t ._get_name_string () } ): '
190
+ f'STALLED: Torrent { t .fields ["id" ]} '
191
+ f'({ t .name } ): '
193
192
f'{ t .progress :.2f} % complete, '
194
193
f'added { naturaldelta (now - t .date_added )} ago, '
195
194
f'started { naturaldelta (now - t .date_started )} ago, '
@@ -199,10 +198,10 @@ def _find_stalled_downloads(self, stalled_days=7, prune_stalled_pct=25):
199
198
if t .progress < prune_stalled_pct :
200
199
logger .info (
201
200
'PRUNING Stalled torrent: %s (%s)' ,
202
- t ._fields ['id' ]. value , t ._get_name_string ()
201
+ t .fields ['id' ], t .name
203
202
)
204
203
self ._client .remove_torrent (
205
- t ._fields ['id' ]. value , delete_data = True
204
+ t .fields ['id' ], delete_data = True
206
205
)
207
206
logger .debug ('%d of %d torrents stalled' , len (stalled ), len (r ))
208
207
return stalled
@@ -218,9 +217,9 @@ def _get_active_torrents(self):
218
217
logger .debug (
219
218
'Torrent %s (%s) - %s, %.2f%% complete; eta=%s '
220
219
'queue_position=%s rateUp=%s rateDown=%s' ,
221
- t ._fields ['id' ]. value , t ._get_name_string () ,
222
- t .status , t .progress , eta , t .queue_position , t .rateUpload ,
223
- t .rateDownload
220
+ t .fields ['id' ], t .name ,
221
+ t .status , t .progress , eta , t .queue_position , t .rate_upload ,
222
+ t .rate_download
224
223
)
225
224
if t .status in ['downloading' , 'download pending' ]:
226
225
active .append (t )
@@ -234,16 +233,16 @@ def _rm_finished_torrents(self):
234
233
for t in r :
235
234
logger .debug (
236
235
'Torrent %s (%s) - %s, %.2f%% complete' ,
237
- t ._fields ['id' ]. value , t ._get_name_string () ,
236
+ t .fields ['id' ], t .name ,
238
237
t .status , t .progress
239
238
)
240
239
if t .status != 'seeding' or t .progress != 100 :
241
240
continue
242
241
logger .info (
243
242
'Removing finished/seeding torrent: %s (%s)' ,
244
- t ._fields ['id' ]. value , t ._get_name_string ()
243
+ t .fields ['id' ], t .name
245
244
)
246
- self ._client .remove_torrent (t ._fields ['id' ]. value )
245
+ self ._client .remove_torrent (t .fields ['id' ])
247
246
248
247
249
248
def parse_args (argv ):
0 commit comments