-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdl_manager.py
More file actions
321 lines (246 loc) · 9.4 KB
/
Copy pathdl_manager.py
File metadata and controls
321 lines (246 loc) · 9.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#!/usr/bin/env python
import logging
import jsonrpclib
import requests
import json
import sys
import os
import shutil
################################
# Config
################################
# Set any feature to False that you do not want
pause_checker = True
app_cleaner = True
nzbget_cleaner = True
folder_cleaner = True
log_level = 'INFO'
# Add any and all paths that you want orphaned downloads to be deleted from
download_paths = {'/mnt/unionfs/downloads/nzbget/completed/radarr4k/',
'/mnt/unionfs/downloads/nzbget/completed/sonarr4k/',
'/mnt/unionfs/downloads/nzbget/completed/radarr/',
'/mnt/unionfs/downloads/nzbget/completed/sonarr/'}
# Add root path outside of docker for downloads
path_swap = '/mnt/unionfs/downloads/nzbget/completed/'
# Nzbget
ssl = True
server_url = 'nzbget.domain.com'
server_port = '443'
username = 'password'
password = 'username'
# Sonarr/Radarr instances you wish to monitor
apps = {'sonarr':
{'url': 'https://sonarr.domain.com:443',
'api': 'xxxxxxxxxxxxxxxxxxxxxx'},
'radarr':
{'url': 'https://radarr.domain.com:443',
'api': 'xxxxxxxxxxxxxxxxxxxxxx'},
'sonarr4k':
{'url': 'https://sonarr4k.domain.com:443',
'api': 'xxxxxxxxxxxxxxxxxxxxxx'},
'radarr4k':
{'url': 'https://radarr4k.domain.com:443',
'api': 'xxxxxxxxxxxxxxxxxxxxxx'}
}
# Add text string for any message you see in radarr/sonarr that you want removing from downloads and blacklisting release.
blacklist_messages = {'File quality does not match quality of the grabbed release', 'sample'}
# remove_messages = {}
################################
# Logging
################################
# Logging format
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
# root logger
logger = logging.getLogger()
# Set initial level
if log_level.upper() == 'DEBUG':
logger.setLevel(logging.DEBUG)
if log_level.upper() == 'INFO':
logger.setLevel(logging.INFO)
if log_level.upper() == 'WARNING':
logger.setLevel(logging.WARNING)
# Console handler, log to stdout
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(formatter)
logger.addHandler(consoleHandler)
# Other modules logging levels
logging.getLogger("requests").setLevel(logging.WARNING)
################################
# Init
################################
if ssl:
protocol = 'https://'
else:
protocol = 'http://'
url = '{}{}:{}@{}:{}/jsonrpc'.format(protocol, username, password, server_url, server_port)
logger.debug('Connecting to nzbget with url: {}'.format(url))
server = jsonrpclib.Server(url)
logger.debug('Server version: {}'.format(server.version()))
serverstatus = server.status()
################################
# Main
################################
def megabyte_gigabyte(input_megabyte):
gigabyte = 1.0 / 1024
convert_gb = gigabyte * input_megabyte
return convert_gb
def bytes_2_human_readable(number_of_bytes):
if number_of_bytes < 0:
raise ValueError("!!! number_of_bytes can't be smaller than 0 !!!")
step_to_greater_unit = 1024.
number_of_bytes = float(number_of_bytes)
unit = 'bytes'
if (number_of_bytes / step_to_greater_unit) >= 1:
number_of_bytes /= step_to_greater_unit
unit = 'KB'
if (number_of_bytes / step_to_greater_unit) >= 1:
number_of_bytes /= step_to_greater_unit
unit = 'MB'
if (number_of_bytes / step_to_greater_unit) >= 1:
number_of_bytes /= step_to_greater_unit
unit = 'GB'
if (number_of_bytes / step_to_greater_unit) >= 1:
number_of_bytes /= step_to_greater_unit
unit = 'TB'
precision = 1
number_of_bytes = round(number_of_bytes, precision)
return str(number_of_bytes) + ' ' + unit
def unpause():
server.resumedownload()
server.resumepost()
server.resumescan()
def pause_check():
down_speed = bytes_2_human_readable(serverstatus['DownloadRate'])
freespace = int(megabyte_gigabyte(serverstatus['FreeDiskSpaceMB']))
if serverstatus['ServerStandBy'] and serverstatus['DownloadPaused']:
if freespace > 0:
logger.debug('Un-pausing as free space is now: {}GB'.format(freespace))
unpause()
if freespace < 0:
logger.debug('Skipping un-pause, free space is still under 100GB ({}GB)'.format(freespace))
if serverstatus['ServerStandBy']:
logger.debug('Nothing to do, nzbget is not paused and que is empty')
else:
logger.debug('Nothing to do, downloads are running with {}GB of free space, at {}/s'.format(freespace,
down_speed))
def app_get_queue(app):
app_name = app
app_url = apps[app]['url']
app_api = apps[app]['api']
headers = {'X-Api-Key': app_api}
r = requests.get(app_url + '/api/queue', headers=headers, timeout=60)
try:
if r.status_code == 401:
logger.warning("Error when connecting to {}, unauthorised. check api/url".format(app_name))
try:
return r.json()
except json.decoder.JSONDecodeError:
logger.warning('{} did not return valid json'.format(app_name))
logger.debug(r.content)
except requests.ConnectionError:
logger.warning('Can not connect to {0} check if {0} is up, or URL is right'.format(app_name))
def app_delete(app, app_id, blacklist):
app_name = app
app_url = apps[app]['url']
app_api = apps[app]['api']
headers = {'X-Api-Key': app_api}
# payload = {'id': app_id, 'blacklist': blacklist}
r = requests.delete(app_url + '/api/queue/{}?blacklist={}'.format(app_id, blacklist),
headers=headers, timeout=30)
try:
if r.status_code == 401:
logger.warning("Error when connecting to {}, unauthorised. check api/url".format(app_name))
try:
return r.json()
except json.decoder.JSONDecodeError:
logger.warning('{} did not return valid json'.format(app_name))
logger.debug(r.content)
except requests.ConnectionError:
logger.warning('Can not connect to {0} check if {0} is up, or URL is right'.format(app_name))
def get_nzbget_data(data_type):
nzbget_list = []
return_list = {}
if data_type == 'queue':
nzbget_data = server.listgroups()
elif data_type == 'history':
nzbget_data = server.history()
else:
return False
for item in nzbget_data:
nzb_id = item['Parameters'][0]['Value']
if nzb_id not in nzbget_list:
nzbget_list.append(nzb_id)
return_list[nzb_id] = item['ID']
return return_list
def app_clean():
for app in apps:
queue = app_get_queue(app)
for item in queue:
if item['protocol'] == 'usenet':
try:
for msg in item['statusMessages'][0]['messages']:
for x in blacklist_messages:
if msg in x:
app_delete(app, item['id'], 'true')
logger.info("Removing {} from {}'s queue and sending to blacklist".format(item['title'], app))
except IndexError:
logger.debug('No status message found')
def nzbget_clean():
history = get_nzbget_data('history')
manager_list = []
for app in apps:
queue = app_get_queue(app)
for id in queue:
if (id['id']) not in manager_list:
manager_list.append(id['id'])
for item in history:
if item not in manager_list:
server.editqueue('HistoryDelete', '', [history[item]])
def delete_dir(path):
shutil.rmtree(path)
def get_local_folders():
subfolders = []
try:
for path in download_paths:
path_list = os.listdir(path)
for x in path_list:
full = '{}{}'.format(path, x)
if os.path.isdir(full):
subfolders.append(full)
return subfolders
except:
logger.info('No such file or directory')
def get_live_folders():
return_list = []
history = server.history()
for item in history:
if item['DestDir'] not in return_list:
return_list.append('{}{}/{}'.format(path_swap, item['DestDir'].split("/")[-2], item['DestDir'].split("/")[-1]))
return return_list
def clean_folders():
local = get_local_folders()
live = get_live_folders()
to_clean = []
for file in local:
if file not in live:
to_clean.append(file)
for orphan in to_clean:
logger.info('Deleting: "{}"'.format(orphan))
delete_dir(orphan)
if __name__ == "__main__":
# Check apps for downloads with warnings and clean as config states
if app_cleaner:
logger.info('App cleaner function is on: Checking now')
app_clean()
# Check if nzbget is paused and resume if enough space
if pause_checker:
logger.info('Pause check function is on: Checking now')
pause_check()
# Check if nzbget history has orphaned items and clear them
if nzbget_cleaner:
logger.info('Nzbget cleaner function is on: Checking now')
nzbget_clean()
# Check if any folders in download are orphaned and delete them
if folder_cleaner:
logger.info('Folder cleaner function is on: Checking now')
clean_folders()