forked from clinton-hall/CP-BackupTool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wanted.py
executable file
·262 lines (230 loc) · 9.1 KB
/
wanted.py
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
#!/usr/bin/env python
import sys
import urllib
import os
import ConfigParser
import json
import argparse
import time
# Default values that will be used if not found in CFG
default_host = 'localhost'
default_port = 5050
default_ssl = False
def validateConf(config, section, item):
try:
# Special check for ssl
if item == 'ssl':
try:
# Specific to CP-backuptool CFG
return config.getboolean(section, item)
except:
# Specific to CP settings.conf
if config.get(section, "ssl_key"):
return True
else:
return False
else:
return config.get(section, item)
except:
if item == 'host':
print "No '%s' found in config, using default: '%s'" % (item, default_host)
return default_host
elif item == 'port':
print "No '%s' found in config, using default: '%s'" % (item, default_port)
return default_port
elif item == 'api_key':
raise Exception("No API key found in configfile")
def writeConf(config, confFile):
with open(confFile, "w") as conf:
config.write(conf)
conf.close()
def apiCall(url, verbose = True):
if verbose:
print "Opening URL:", url
try:
urlObj = urllib.urlopen(url)
except:
print "Failed to open URL:", url
print "Caught following:"
raise
result = json.load(urlObj)
if result:
return result
else:
return None
def listWanted(baseurl):
api_call = "movie.list/?status=active"
url = baseurl + api_call
result = apiCall(url)
return result
def listDone(baseurl):
api_call = "movie.list/?status=done"
url = baseurl + api_call
result = apiCall(url)
return result
def listLimitedDone(baseurl):
api_call = "movie.list/?status=manage&limit_offset=50"
url = baseurl + api_call
result = apiCall(url)
return result
def process(type, backup = None):
config = ConfigParser.ConfigParser()
if args.cfg:
configFilename = args.cfg
else:
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "couch.cfg")
print "Loading config from:", configFilename
with open(configFilename, "r") as conf:
config.readfp(conf)
sections = config.sections()
host = validateConf(config, sections[0], "host")
port = validateConf(config, sections[0], "port")
apikey = validateConf(config, sections[0], "api_key")
ssl = validateConf(config, sections[0], "ssl")
web_root = validateConf(config, sections[0], "url_base")
if ssl:
protocol = "https://"
else:
protocol = "http://"
# Add '/' to beginning of web_root if missing
if web_root and not web_root[0] == '/':
web_root = '/' + web_root
# Remove '/' from end of web_root if present
if web_root and web_root[-1] == '/':
web_root = web_root[:-1]
# The base URL
baseurl = protocol + host + ":" + str(port) + web_root + "/api/" + apikey + "/"
if type == "backup":
result = listWanted(baseurl)
backup_list = []
# Check if backup is necessary (i.e skip if no movies found)
if result['total'] > 0:
for item in result["movies"]:
if not ("info" in item or "identifiers" in item):
continue
movie_list = []
try:
# Try the current data structure
movie_list.append(item["identifiers"]["imdb"])
except:
# Use old data structure for backward compatibility
movie_list.append(item["info"]["imdb"])
# If the profile ID is found (optional)
if item["profile_id"]:
movie_list.append(item["profile_id"])
# Append the movie list to backup list
backup_list.append(movie_list)
print "found %s wanted movies, writing file..." % len(backup_list)
with open(backup, 'w') as f:
json.dump(backup_list, f)
f.close()
print "Backup file completed:", backup
else:
print "No wanted movies found"
elif type == "restore":
# Do a managed search prior to restoring
print "Doing a full managed scan..."
api_call = "manage.update/?full=1"
url = baseurl + api_call
result = apiCall(url)
# Check progress
api_call = "manage.progress"
url = baseurl + api_call
result = apiCall(url)
while result['progress'] != False:
result = apiCall(url, verbose=False)
time.sleep(1)
print "Managed scan completed"
with open(backup, 'r') as f:
movie_list = json.load(f)
f.close()
for movie in movie_list:
# Add movies along with profile id (if not found or empty; default will be used)
if len(movie) == 1:
movie.append("")
api_call = "movie.add/?identifier=%s&profile_id=%s" %(movie[0], movie[1])
url = baseurl + api_call
result = apiCall(url)
elif type == "add":
with open(backup, 'r') as f:
movie_list = json.load(f)
f.close()
for movie in movie_list:
# Add movies along with profile id (if not found or empty; default will be used)
if len(movie) == 1:
movie.append("")
api_call = "movie.add/?identifier=%s&profile_id=%s" %(movie[0], movie[1])
url = baseurl + api_call
result = apiCall(url)
elif type == "clear":
result = listLimitedDone(baseurl)
print "Clearing Movie Library..."
if not result['empty']:
while not result['empty']:
for item in result["movies"]:
print "Clearing movie '%s' from Library" % item["title"]
api_call = "movie.delete/?delete_from=manage&id=%s" % item["_id"]
url = baseurl + api_call
apiCall(url, verbose = False)
result = listLimitedDone(baseurl)
else:
print "No movies in Library to clear"
elif type == "delete":
result = listWanted(baseurl)
if result['total'] > 0:
print "Deleting wanted movies..."
for item in result["movies"]:
print "Deleting movie '%s'" % item["title"]
api_call = "movie.delete/?delete_from=wanted&id=%s" % item["_id"]
url = baseurl + api_call
apiCall(url, verbose = False)
else:
print "No wanted movies to delete"
elif type == "export":
result = listDone(baseurl)
export_list = []
# Check if export is necessary (i.e skip if no movies found)
if result['total'] > 0:
for item in result["movies"]:
if not ("info" in item or "identifiers" in item):
continue
movie_list = []
try:
# Try the current data structure
movie_list.append(item["identifiers"]["imdb"])
except:
# Use old data structure for backward compatibility
movie_list.append(item["info"]["imdb"])
# Check releases for files
for release in item["releases"]:
if not ("files" in release):
continue
# Get the path of the movie file
movie_list.append(release["files"]["movie"][0])
# Append separator character (optional)
movie_list.append("\n")
# Append the movie list to export list
export_list.append(movie_list)
print "found %s library movies, writing file..." % len(export_list)
with open(backup, 'w') as f:
json.dump(export_list, f)
f.close()
print "Export file completed:", backup
else:
print "No library movies found"
parser = argparse.ArgumentParser(description='Backup/Restore/Delete/Export Couchpotato wanted/library list',
formatter_class=argparse.RawTextHelpFormatter)
# Require this option
parser.add_argument('--type', metavar='backup/restore/delete/add/export/clear', choices=['backup', 'restore', 'delete', 'add', 'export', 'clear'],
required=True, help='''backup: Writes the wanted movies to file.
restore: Adds wanted movies from file.
delete: Delete all your wanted movies
add: Adds wanted movies from file skipping manage scan.
export: Writes the library movies to file.''')
parser.add_argument('--file', help='', required=False)
parser.add_argument('--cfg', metavar='cfg-file', help='Specify an alternative cfg file')
args = parser.parse_args()
if args.type == 'backup' or args.type == 'restore' or args.type == 'export':
if not args.file:
parser.error('You must specify a file when using %s' % args.type)
process(args.type, args.file)