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 #!/usr/bin/env python3
from hashlib import sha1 from hashlib import sha1
from base64 import b64encode 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 from xml.dom.minidom import parse
import sys import sys
import vlc import vlc
...@@ -31,6 +33,31 @@ class Asset(object): ...@@ -31,6 +33,31 @@ class Asset(object):
while buffer: while buffer:
hash.update (buffer) hash.update (buffer)
buffer = fh.read (buffersize) 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 ()) return (self.hash == b64encode (hash.digest ()).decode ())
def add_duration (self): def add_duration (self):
...@@ -40,7 +67,8 @@ class Asset(object): ...@@ -40,7 +67,8 @@ class Asset(object):
media.parse () media.parse ()
self.duration = media.get_duration () 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.''' '''Initialize an asset, has to have a filename and path.'''
self.rootpath = rootpath self.rootpath = rootpath
if filename[0:8] == 'file:///': if filename[0:8] == 'file:///':
...@@ -68,7 +96,7 @@ class DCP: ...@@ -68,7 +96,7 @@ class DCP:
if asset.verifySize () == False: if asset.verifySize () == False:
return False return False
except BaseException as e: except BaseException as e:
raise RuntimeError ('Failed size comparisement for ' + raise RuntimeError ('Failed size comparisement for ' +\
asset.filename) from e asset.filename) from e
#Sort the assets by size before calculating hashes, for performance. #Sort the assets by size before calculating hashes, for performance.
def sortkey(x): def sortkey(x):
...@@ -82,7 +110,7 @@ class DCP: ...@@ -82,7 +110,7 @@ class DCP:
if asset.verifyHash () == False: if asset.verifyHash () == False:
return False return False
except BaseException as e: except BaseException as e:
raise RuntimeError ('Failed hash calculation for ' + raise RuntimeError ('Failed hash calculation for ' +\
asset.filename) from e asset.filename) from e
return True return True
...@@ -105,9 +133,11 @@ class DCP: ...@@ -105,9 +133,11 @@ class DCP:
filename = element.getElementsByTagName ('Path')[0].firstChild.data filename = element.getElementsByTagName ('Path')[0].firstChild.data
packinglist = len (element.getElementsByTagName ('PackingList')) > 0 packinglist = len (element.getElementsByTagName ('PackingList')) > 0
if packinglist: 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: 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: except BaseException as e:
raise RuntimeError ('Failed to parse assetmap file') from e raise RuntimeError ('Failed to parse assetmap file') from e
...@@ -131,7 +161,8 @@ class DCP: ...@@ -131,7 +161,8 @@ class DCP:
self.signed = len (pkl.getElementsByTagName ('Signer')) > 0 self.signed = len (pkl.getElementsByTagName ('Signer')) > 0
try: try:
if hasattr (self, 'name') == False: if hasattr (self, 'name') == False:
self.name = pkl.getElementsByTagName('AnnotationText')[0].firstChild.data.strip() self.name = pkl.getElementsByTagName\
('AnnotationText')[0].firstChild.data.strip()
except: except:
pass pass
for element in pkl.getElementsByTagName ('Asset'): for element in pkl.getElementsByTagName ('Asset'):
...@@ -140,7 +171,8 @@ class DCP: ...@@ -140,7 +171,8 @@ class DCP:
hash = element.getElementsByTagName ('Hash')[0].firstChild.data hash = element.getElementsByTagName ('Hash')[0].firstChild.data
type = element.getElementsByTagName ('Type')[0].firstChild.data type = element.getElementsByTagName ('Type')[0].firstChild.data
size = int(element.getElementsByTagName ('Size')[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.hash = hash
asset.size = size asset.size = size
asset.type = type asset.type = type
...@@ -155,13 +187,47 @@ class DCP: ...@@ -155,13 +187,47 @@ class DCP:
self._add_volindex () self._add_volindex ()
self._parse_packinglist () self._parse_packinglist ()
try: 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: except:
self.duration = 'Unknown' 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 __name__ == '__main__':
if (len(sys.argv) == 2): if len (sys.argv) == 2:
dcp = DCP (sys.argv[1]) dcp = DCP (sys.argv[1])
else: else:
dcp = DCP ('./') dcp = DCP ('./')
...@@ -174,7 +240,7 @@ if __name__ == '__main__': ...@@ -174,7 +240,7 @@ if __name__ == '__main__':
else: else:
print ('DCP is unsigned') print ('DCP is unsigned')
print ('Duration:', dcp.duration) print ('Duration:', dcp.duration)
if (dcp.verify()): if dcp.verify ():
print ('Verification succeeded.') print ('Verification succeeded.')
else: else:
print ('Verification failed.') print ('Verification failed.')
......
...@@ -6,6 +6,8 @@ from PyQt4 import QtCore ...@@ -6,6 +6,8 @@ from PyQt4 import QtCore
from dcp import DCP from dcp import DCP
import ui import ui
import sys import sys
import syslog
import time
class verifyThread(QtCore.QThread): class verifyThread(QtCore.QThread):
'''A seperate thread to verify the DCP (IO intensive). '''A seperate thread to verify the DCP (IO intensive).
...@@ -20,8 +22,12 @@ class verifyThread(QtCore.QThread): ...@@ -20,8 +22,12 @@ class verifyThread(QtCore.QThread):
result = dcp.verify() result = dcp.verify()
if result: if result:
window.verifyLine.setText('OK') window.verifyLine.setText('OK')
syslog.syslog (syslog.LOG_INFO, time.ctime () + dcp.name +\
' verification succeeded.')
else: else:
window.verifyLine.setText('Corrupted!') window.verifyLine.setText('Corrupted!')
syslog.syslog (syslog.LOG_INFO, time.ctime () + dcp.name +\
' verification failed.')
except BaseException as exception: except BaseException as exception:
window.verifyLine.setText(str(exception)) window.verifyLine.setText(str(exception))
...@@ -38,6 +44,7 @@ def verify_in_thread(): ...@@ -38,6 +44,7 @@ def verify_in_thread():
if __name__ == '__main__': if __name__ == '__main__':
syslog.openlog (ident = 'dcpman', facility = syslog.LOG_USER)
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
icon = QtGui.QIcon('/usr/share/icons/oxygen/16x16/apps/kmplayer.png') icon = QtGui.QIcon('/usr/share/icons/oxygen/16x16/apps/kmplayer.png')
app.setWindowIcon(icon) app.setWindowIcon(icon)
...@@ -51,8 +58,18 @@ if __name__ == '__main__': ...@@ -51,8 +58,18 @@ if __name__ == '__main__':
dcp = DCP(directory) dcp = DCP(directory)
try: try:
window.nameLine.setText(dcp.name) window.nameLine.setText(dcp.name)
syslog.syslog (syslog.INFO, time.ctime () + dcp.name +\
'parsed.')
except AttributeError: except AttributeError:
window.nameLine.setText(directory.split('/')[-1]) 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: if dcp.signed and dcp.duration == 0:
window.encryptedLine.setText('Most likely') window.encryptedLine.setText('Most likely')
elif dcp.signed or dcp.duration == 0: 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