Skip to content
Snippets Groups Projects
Commit b31f724e authored by nimrod's avatar nimrod
Browse files

Work on future feature (full ingest of DCP from removable media).

parent 234ffe5b
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python3
from hashlib import sha1
from base64 import b64encode
from os import stat, listdir
from os import stat, listdir, mkdir, statvfs
from os.path import isdir, basename
from shutil import copyfile
from xml.dom.minidom import parse
import sys
import vlc
......@@ -31,6 +33,31 @@ class Asset(object):
while buffer:
hash.update (buffer)
buffer = fh.read (buffersize)
fh.close ()
return (self.hash == b64encode (hash.digest ()).decode ())
def copyAndVerify (self, destination):
'''Copies the file to the destination directory and verifies the hash
during.'''
newfilepath = destination + '/' + self.filename
if hasattr (self, 'hash') == False:
copyfile (self.fullpath, newfilepath)
self.fullpath = newfilepath
self.rootpath = destination
return True
buffersize = 2 ** 16
in_fh = open (self.fullpath, 'rb')
out_fh = open (newfullpath, 'wb')
buffer = in_fh.read (buffersize)
hash = sha1 ()
while buffer:
hash.update (buffer)
out_fh.write (buffer)
buffer = in_fh.read (buffersize)
in_fh.close ()
out_fh.close ()
self.rootpath = destination
self.fullpath = newfullpath
return (self.hash == b64encode (hash.digest ()).decode ())
def add_duration (self):
......@@ -40,7 +67,8 @@ class Asset(object):
media.parse ()
self.duration = media.get_duration ()
def __init__(self, rootpath, filename, id=None, hash=None, size=None, packinglist=False, type=None):
def __init__(self, rootpath, filename, id=None, hash=None, size=None,\
packinglist=False, type=None):
'''Initialize an asset, has to have a filename and path.'''
self.rootpath = rootpath
if filename[0:8] == 'file:///':
......@@ -68,7 +96,7 @@ class DCP:
if asset.verifySize () == False:
return False
except BaseException as e:
raise RuntimeError ('Failed size comparisement for ' +
raise RuntimeError ('Failed size comparisement for ' +\
asset.filename) from e
#Sort the assets by size before calculating hashes, for performance.
def sortkey(x):
......@@ -82,7 +110,7 @@ class DCP:
if asset.verifyHash () == False:
return False
except BaseException as e:
raise RuntimeError ('Failed hash calculation for ' +
raise RuntimeError ('Failed hash calculation for ' +\
asset.filename) from e
return True
......@@ -105,9 +133,11 @@ class DCP:
filename = element.getElementsByTagName ('Path')[0].firstChild.data
packinglist = len (element.getElementsByTagName ('PackingList')) > 0
if packinglist:
self.assets.append(Asset(self.directory, filename, id=id, packinglist=packinglist, type='text/xml'))
self.assets.append (Asset (self.directory, filename,\
id=id, packinglist=packinglist, type='text/xml'))
else:
self.assets.append(Asset(self.directory, filename, id=id, packinglist=packinglist))
self.assets.append (Asset (self.directory, filename,\
id=id, packinglist=packinglist))
except BaseException as e:
raise RuntimeError ('Failed to parse assetmap file') from e
......@@ -131,7 +161,8 @@ class DCP:
self.signed = len (pkl.getElementsByTagName ('Signer')) > 0
try:
if hasattr (self, 'name') == False:
self.name = pkl.getElementsByTagName('AnnotationText')[0].firstChild.data.strip()
self.name = pkl.getElementsByTagName\
('AnnotationText')[0].firstChild.data.strip()
except:
pass
for element in pkl.getElementsByTagName ('Asset'):
......@@ -140,7 +171,8 @@ class DCP:
hash = element.getElementsByTagName ('Hash')[0].firstChild.data
type = element.getElementsByTagName ('Type')[0].firstChild.data
size = int(element.getElementsByTagName ('Size')[0].firstChild.data)
asset = [x for x in self.assets if hasattr(x, 'id') and x.id == id][0]
asset = [x for x in self.assets if hasattr (x, 'id') and\
x.id == id][0]
asset.hash = hash
asset.size = size
asset.type = type
......@@ -155,13 +187,47 @@ class DCP:
self._add_volindex ()
self._parse_packinglist ()
try:
self.duration = max ([x.duration for x in self.assets if hasattr (x, 'duration')])
self.duration = max ([x.duration for x in self.assets if hasattr\
(x, 'duration')])
except:
self.duration = 'Unknown'
def copyAndVerify (self, destination):
'''Copies the DCP to the destination directory and verifies during.'''
for asset in self.assets:
totalsize = stat (asset.fullpath).st_size
try:
if asset.verifySize () == False:
return False
except BaseException as e:
raise RuntimeError ('Failed size comparisement for ' +\
asset.filename) from e
freespace = statvfs (destination).f_bavail * statvfs\
(destination).f_bsize
if freespace < totalsize:
return False
#Sort the assets by size before calculating hashes, for performance.
def sortkey(x):
try:
return x.size
except AttributeError:
return 0
self.assets.sort (key=sortkey)
newdirectory = destination + '/' + basename (self.directory)
mkdir (newdirectory)
for asset in self.assets:
try:
if asset.copyAndVerify (newdirectory) == False:
return False
except BaseException as e:
raise RuntimeError ('Failed hash calculation for ' +\
asset.filename) from e
self.directory = newdirectory
return True
if __name__ == '__main__':
if (len(sys.argv) == 2):
if len (sys.argv) == 2:
dcp = DCP (sys.argv[1])
else:
dcp = DCP ('./')
......@@ -174,7 +240,7 @@ if __name__ == '__main__':
else:
print ('DCP is unsigned')
print ('Duration:', dcp.duration)
if (dcp.verify()):
if dcp.verify ():
print ('Verification succeeded.')
else:
print ('Verification failed.')
......
......@@ -6,6 +6,8 @@ from PyQt4 import QtCore
from dcp import DCP
import ui
import sys
import syslog
import time
class verifyThread(QtCore.QThread):
'''A seperate thread to verify the DCP (IO intensive).
......@@ -20,8 +22,12 @@ class verifyThread(QtCore.QThread):
result = dcp.verify()
if result:
window.verifyLine.setText('OK')
syslog.syslog (syslog.LOG_INFO, time.ctime () + dcp.name +\
' verification succeeded.')
else:
window.verifyLine.setText('Corrupted!')
syslog.syslog (syslog.LOG_INFO, time.ctime () + dcp.name +\
' verification failed.')
except BaseException as exception:
window.verifyLine.setText(str(exception))
......@@ -38,6 +44,7 @@ def verify_in_thread():
if __name__ == '__main__':
syslog.openlog (ident = 'dcpman', facility = syslog.LOG_USER)
app = QtGui.QApplication(sys.argv)
icon = QtGui.QIcon('/usr/share/icons/oxygen/16x16/apps/kmplayer.png')
app.setWindowIcon(icon)
......@@ -51,8 +58,18 @@ if __name__ == '__main__':
dcp = DCP(directory)
try:
window.nameLine.setText(dcp.name)
syslog.syslog (syslog.INFO, time.ctime () + dcp.name +\
'parsed.')
except AttributeError:
window.nameLine.setText(directory.split('/')[-1])
if dcp.signed:
syslog.syslog (syslog.INFO, time.ctime () + dcp.name +\
' is signed.')
else:
syslog.syslog (syslog.INFO, time.ctime () + dcp.name +\
' is not sigend.')
syslog.syslog (syslog.INFO, time.ctime () + dcp.name +\
' duration is ' + dcp.duration)
if dcp.signed and dcp.duration == 0:
window.encryptedLine.setText('Most likely')
elif dcp.signed or dcp.duration == 0:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment