1 # -*- coding: utf-8 -*-
6 import logging.handlers
12 from ConfigParser import SafeConfigParser
13 from datetime import date
17 from suds.client import Client
18 from suds.transport.http import HttpAuthenticated
23 # Initializes the logger, log, and gives it a name, name
24 def init_logger(name):
25 form = "[%(asctime)s] - %(levelname)8s - %(funcName)15s()] %(message)s"
26 datefmt = '%Y-%m-%d %H:%M:%S'
27 l = logging.getLogger(name)
28 handler = logging.handlers.SysLogHandler(
29 facility=logging.handlers.SysLogHandler.LOG_LOCAL0, address='/dev/log')
31 formatter = logging.Formatter(form, datefmt=datefmt)
32 handler.setFormatter(formatter)
35 # Authenticates and returns the connection
36 def connect(usern, passwd):
37 trans = HttpAuthenticated(username=usern, password=passwd)
38 url = "https://vidyo-replay1.uio.no/replay/services/VidyoReplayContentManagementService?wsdl"
39 loc = "https://vidyo-replay1.uio.no/replay/services/VidyoReplayContentManagementService"
40 return Client(url, location=loc, transport=trans, faults=False)
43 # Returns the records from VidyoReplay
44 # def get_records(client):
45 def get_records(client):
47 records = client.service.RecordsSearch(sortby='date')
48 except Exception as detail:
49 s = "Exception: {}".format(detail)
55 # Checks if the script has the right amount of arguments
56 def check_cmd_args(argv):
57 if len(argv) is not 2:
58 log.error("1 argument needed, found %d", len(argv)-1)
62 # Check to see if the recording is owned by the "tsd-import" user.
63 def check_username(rec):
64 username = 'tsd-import'
66 if rec.userName == username:
72 # Returns True if there is not enough space for the record.
73 def check_usage(path, filesize):
75 free = st.f_bavail * st.f_frsize
83 # Checks if the script is already running
84 def single_instance(path):
88 LOCK = open(path, 'w+')
90 s = "IOError: {}".format(e)
95 fcntl.lockf(LOCK, fcntl.LOCK_EX | fcntl.LOCK_NB)
97 s = "the script is already running"
102 # Returns true if the user har permissions to read directory d
104 if not os.path.isdir(d):
105 s = "{} is not a directory".format(d)
109 if not os.access(d, os.R_OK):
110 s = "No permission to read in directory {}".format(d)
117 # Returns true if the user har permissions to write to directory d
121 if not os.access(d, os.W_OK):
122 s = "No permission to write in directory: {}".format(d)
129 # Returns true if the user har permissions to write to file f
131 if not os.access(f, os.W_OK):
132 s = "No permission to write to file: {}".format(f)
140 def read_config(argv):
143 if not os.path.isfile(config_f):
144 s = "{} does not exist".format(config_f)
148 parser = SafeConfigParser()
149 parser.read(config_f)
153 'usern': parser.get('auth', 'username'),
154 'passwd': parser.get('auth', 'password'),
155 'lock': parser.get('config', 'lock'),
156 'dest': parser.get('config', 'videoDest'),
157 'delete': parser.getboolean('config', 'delete'),
158 'dryrun': parser.getboolean('config', 'dryrun')
161 s = "configuration error: {}".format(sys.exc_info()[0])
166 print "--- Config ---"
171 config['hash'] = parser.get('config', 'hash') # not mandatory
173 config['hash'] = 'sha256'
176 if not os.path.isfile(config['lock']):
177 s = "{} does not exist".format(config['lock'])
181 write_file(config['lock'])
182 write_dir(config['dest'])
184 if not os.path.isdir(config['dest']+"completed"):
185 os.mkdir(config['dest']+"completed", 0770)
190 # Makes a JSON-file from record metadata
191 def makeJSON(record, dest, display_name, checksum, hashfunc, dryrun):
196 'tenantName': record.tenantName,
197 'userName': record.userName,
198 'userFullName': record.userFullName,
199 'recordedBy': display_name,
200 'dateCreated': record.dateCreated.strftime("%Y-%m-%d %H:%M:%S"),
201 'dateCreatedString': record.dateCreatedString,
202 # 'endTime': record.endTime,
203 'duration': record.duration,
204 'resolution': record.resolution,
205 'framerate': record.framerate,
207 'recordScope': record.recordScope,
208 'title': record.title,
209 'roomName': record.roomName,
210 'fileLink': record.fileLink,
211 'recorderId': record.recorderId,
212 'webcast': record.webcast,
214 'comments': record.comments,
215 'locked': record.locked,
216 'externalPlaybackLink': record.externalPlaybackLink,
217 'fileSize': record.fileSize,
218 'checksum': checksum,
219 'hashfunc': hashfunc,
225 print "Checksum is always -2 with dryrun"
229 if os.path.isfile(dest):
230 oldfp = open(dest, 'r')
231 oldjson = json.load(oldfp)
237 with open(dest, 'w') as f:
241 def checksum_and_download(path, hashfunc, f):
245 with open(path, 'ab') as afile:
246 buf = f.read(BLOCKSIZE)
249 csum = zlib.crc32(buf, csum)
250 buf = f.read(BLOCKSIZE)
251 return csum & 0xffffffff
255 hasher = hashlib.sha256()
256 with open(path, 'ab') as afile:
257 buf = f.read(BLOCKSIZE)
261 buf = f.read(BLOCKSIZE)
262 return hasher.hexdigest()
264 if hashfunc == 'crc32':
270 def getVideo(config, url):
271 username = config['usern']
272 passwd = config['passwd']
273 dest = config['dest']
274 hashfunc = config['hash']
275 dryrun = config['dryrun']
277 req = urllib2.Request(url)
278 base64string = base64.encodestring('%s:%s' % (username, passwd))[:-1]
279 req.add_header("Authorization", "Basic %s" % base64string)
282 f = urllib2.urlopen(req)
283 condis = f.info()['Content-Disposition']
284 result = re.search('\"(.*)\"', condis)
285 filename = result.group(1)
291 elif os.path.isfile(dest+"completed/"+filename):
294 checks = checksum_and_download(dest+filename, hashfunc, f)
295 return filename, checks
298 def run(config, client, records):
299 username = config['usern']
300 passwd = config['passwd']
301 dest = config['dest']
302 delete = config['delete']
303 hashfunc = config['hash']
304 dryrun = config['dryrun']
306 for record in records[1].records:
307 if check_username(record):
308 if not check_usage(config['dest'], int(record.fileSize)):
309 s = "Disk space full. Record.id: {} Filesize: {}".format(record.id, record.fileSize)
314 print "--- ID: {} ---".format(record.id)
316 filename, checksum = getVideo(config, record.fileLink)
317 result = re.search('(.*)_\d\d\d\d', filename)
321 shutil.move(dest+filename, dest+"completed/"+filename)
322 makeJSON(record, dest +"completed/"+filename[:-4] + '.json',
323 result.group(1), checksum, hashfunc, dryrun)
326 # elif checksum == -1 and delete == True:
327 # s = "The file {} already exist. delete = {}".format(dest+filename, delete)
330 if dryrun and delete:
331 print "Record would be deleted"
333 retval = client.service.DeleteRecord(record.id)
334 if retval[1] != "OK":
335 s = "DeleteRecord({}) should return (200, OK). Returned {}.".format(
342 if __name__ == "__main__":
344 log = logging.getLogger('log')
345 check_cmd_args(sys.argv)
346 config = read_config(sys.argv[1:])
347 single_instance(config['lock'])
349 client = connect(config['usern'], config['passwd'])
350 records = get_records(client)
351 run(config, client, records)