diff --git a/comicarchive.py b/comicarchive.py index 1b146bf..00477b3 100644 --- a/comicarchive.py +++ b/comicarchive.py @@ -52,7 +52,7 @@ class ZipArchiver: return comment def setArchiveComment( self, comment ): - self.writeZipComment( self.path, comment ) + return self.writeZipComment( self.path, comment ) def readArchiveFile( self, archive_file ): zf = zipfile.ZipFile( self.path, 'r' ) @@ -61,19 +61,28 @@ class ZipArchiver: return data def removeArchiveFile( self, archive_file ): - self.rebuildZipFile( [ archive_file ] ) - + try: + self.rebuildZipFile( [ archive_file ] ) + except: + return False + else: + return True + def writeArchiveFile( self, archive_file, data ): # At the moment, no other option but to rebuild the whole # zip archive w/o the indicated file. Very sucky, but maybe # another solution can be found - self.rebuildZipFile( [ archive_file ] ) - - #now just add the archive file as a new one - zf = zipfile.ZipFile(self.path, mode='a', compression=zipfile.ZIP_DEFLATED ) - zf.writestr( archive_file, data ) - zf.close() - + try: + self.rebuildZipFile( [ archive_file ] ) + + #now just add the archive file as a new one + zf = zipfile.ZipFile(self.path, mode='a', compression=zipfile.ZIP_DEFLATED ) + zf.writestr( archive_file, data ) + zf.close() + return True + except: + return False + def getArchiveFilenameList( self ): zf = zipfile.ZipFile( self.path, 'r' ) namelist = zf.namelist() @@ -85,7 +94,7 @@ class ZipArchiver: # TODO: use tempfile.mkstemp # this recompresses the zip archive, without the files in the exclude_list - print "Rebuilding zip {0} without {1}".format( self.path, exclude_list ) + #print "Rebuilding zip {0} without {1}".format( self.path, exclude_list ) # generate temp file tmp_fd, tmp_name = tempfile.mkstemp( dir=os.path.dirname(self.path) ) @@ -123,50 +132,54 @@ class ZipArchiver: statinfo = os.stat(filename) file_length = statinfo.st_size - fo = open(filename, "r+b") + try: + fo = open(filename, "r+b") - #the starting position, relative to EOF - pos = -4 + #the starting position, relative to EOF + pos = -4 - found = False - value = bytearray() - - # walk backwards to find the "End of Central Directory" record - while ( not found ) and ( -pos != file_length ): - # seek, relative to EOF - fo.seek( pos, 2) - - value = fo.read( 4 ) - - #look for the end of central directory signature - if bytearray(value) == bytearray([ 0x50, 0x4b, 0x05, 0x06 ]): - found = True - else: - # not found, step back another byte - pos = pos - 1 - #print pos,"{1} int: {0:x}".format(bytearray(value)[0], value) + found = False + value = bytearray() - if found: - - # now skip forward 20 bytes to the comment length word - pos += 20 - fo.seek( pos, 2) + # walk backwards to find the "End of Central Directory" record + while ( not found ) and ( -pos != file_length ): + # seek, relative to EOF + fo.seek( pos, 2) - # Pack the length of the comment string - format = "H" # one 2-byte integer - comment_length = struct.pack(format, len(comment)) # pack integer in a binary string - - # write out the length - fo.write( comment_length ) - fo.seek( pos+2, 2) - - # write out the comment itself - fo.write( comment ) - fo.truncate() - fo.close() + value = fo.read( 4 ) + #look for the end of central directory signature + if bytearray(value) == bytearray([ 0x50, 0x4b, 0x05, 0x06 ]): + found = True + else: + # not found, step back another byte + pos = pos - 1 + #print pos,"{1} int: {0:x}".format(bytearray(value)[0], value) + + if found: + + # now skip forward 20 bytes to the comment length word + pos += 20 + fo.seek( pos, 2) + + # Pack the length of the comment string + format = "H" # one 2-byte integer + comment_length = struct.pack(format, len(comment)) # pack integer in a binary string + + # write out the length + fo.write( comment_length ) + fo.seek( pos+2, 2) + + # write out the comment itself + fo.write( comment ) + fo.truncate() + fo.close() + else: + raise Exception('Failed to write comment to zip file!') + except: + return False else: - raise Exception('Failed to write comment to zip file!') + return True #------------------------------------------ # RAR implementation @@ -196,22 +209,29 @@ class RarArchiver: def setArchiveComment( self, comment ): if self.rar_exe_path is not None: - # write comment to temp file - tmp_fd, tmp_name = tempfile.mkstemp() - f = os.fdopen(tmp_fd, 'w+b') - f.write( comment ) - f.close() + try: + # write comment to temp file + tmp_fd, tmp_name = tempfile.mkstemp() + f = os.fdopen(tmp_fd, 'w+b') + f.write( comment ) + f.close() - # use external program to write comment to Rar archive - subprocess.call([self.rar_exe_path, 'c', '-c-', '-z' + tmp_name, self.path], - startupinfo=self.startupinfo, - stdout=self.devnull) - - if platform.system() == "Darwin": - time.sleep(1) + # use external program to write comment to Rar archive + subprocess.call([self.rar_exe_path, 'c', '-c-', '-z' + tmp_name, self.path], + startupinfo=self.startupinfo, + stdout=self.devnull) - os.remove( tmp_name) - + if platform.system() == "Darwin": + time.sleep(1) + + os.remove( tmp_name) + except: + return False + else: + return True + else: + return False + def readArchiveFile( self, archive_file ): entries = UnRAR2.RarFile( self.path ).read_files( archive_file ) @@ -225,36 +245,48 @@ class RarArchiver: def writeArchiveFile( self, archive_file, data ): if self.rar_exe_path is not None: + try: + tmp_folder = tempfile.mkdtemp() + + tmp_file = os.path.join( tmp_folder, archive_file ) + + f = open(tmp_file, 'w') + f.write( data ) + f.close() + + # use external program to write file to Rar archive + subprocess.call([self.rar_exe_path, 'a', '-c-', '-ep', self.path, tmp_file], + startupinfo=self.startupinfo, + stdout=self.devnull) + + if platform.system() == "Darwin": + time.sleep(1) + os.remove( tmp_file) + os.rmdir( tmp_folder) + except: + return False + else: + return True + else: + return False - tmp_folder = tempfile.mkdtemp() - - tmp_file = os.path.join( tmp_folder, archive_file ) - - f = open(tmp_file, 'w') - f.write( data ) - f.close() - - # use external program to write file to Rar archive - subprocess.call([self.rar_exe_path, 'a', '-c-', '-ep', self.path, tmp_file], - startupinfo=self.startupinfo, - stdout=self.devnull) - - if platform.system() == "Darwin": - time.sleep(1) - os.remove( tmp_file) - os.rmdir( tmp_folder) - def removeArchiveFile( self, archive_file ): if self.rar_exe_path is not None: + try: + # use external program to remove file from Rar archive + subprocess.call([self.rar_exe_path, 'd','-c-', self.path, archive_file], + startupinfo=self.startupinfo, + stdout=self.devnull) - # use external program to remove file from Rar archive - subprocess.call([self.rar_exe_path, 'd','-c-', self.path, archive_file], - startupinfo=self.startupinfo, - stdout=self.devnull) - - if platform.system() == "Darwin": - time.sleep(1) - + if platform.system() == "Darwin": + time.sleep(1) + except: + return False + else: + return True + else: + return False + def getArchiveFilenameList( self ): rarc = UnRAR2.RarFile( self.path ) @@ -273,7 +305,7 @@ class FolderArchiver: return self.readArchiveFile( self.comment_file_name ) def setArchiveComment( self, comment ): - self.writeArchiveFile( self.comment_file_name, comment ) + return self.writeArchiveFile( self.comment_file_name, comment ) def readArchiveFile( self, archive_file ): @@ -295,8 +327,10 @@ class FolderArchiver: with open(fname, 'w+') as f: f.write( data ) f.close() - except IOError as e: - pass + except: + return False + else: + return True def removeArchiveFile( self, archive_file ): @@ -304,7 +338,9 @@ class FolderArchiver: try: os.remove( fname ) except: - pass + return False + else: + return True def getArchiveFilenameList( self ): return self.listFiles( self.path ) @@ -330,13 +366,13 @@ class UnknownArchiver: def getArchiveComment( self ): return "" def setArchiveComment( self, comment ): - return + return False def readArchiveFilen( self ): return "" def writeArchiveFile( self, archive_file, data ): - return + return False def removeArchiveFile( self, archive_file ): - return + return False def getArchiveFilenameList( self ): return [] @@ -440,9 +476,9 @@ class ComicArchive: def writeMetadata( self, metadata, style ): if style == MetaDataStyle.CIX: - self.writeCIX( metadata ) + return self.writeCIX( metadata ) elif style == MetaDataStyle.CBI: - self.writeCBI( metadata ) + return self.writeCBI( metadata ) def hasMetadata( self, style ): @@ -455,9 +491,9 @@ class ComicArchive: def removeMetadata( self, style ): if style == MetaDataStyle.CIX: - self.removeCIX() + return self.removeCIX() elif style == MetaDataStyle.CBI: - self.removeCBI() + return self.removeCBI() def getCoverPage(self): @@ -522,10 +558,10 @@ class ComicArchive: def writeCBI( self, metadata ): cbi_string = ComicBookInfo().stringFromMetadata( metadata ) - self.archiver.setArchiveComment( cbi_string ) + return self.archiver.setArchiveComment( cbi_string ) def removeCBI( self ): - self.archiver.setArchiveComment( "" ) + return self.archiver.setArchiveComment( "" ) def readCIX( self ): raw_cix = self.readRawCIX() @@ -545,11 +581,13 @@ class ComicArchive: if metadata is not None: cix_string = ComicInfoXml().stringFromMetadata( metadata ) - self.archiver.writeArchiveFile( self.ci_xml_filename, cix_string ) - + return self.archiver.writeArchiveFile( self.ci_xml_filename, cix_string ) + else: + return False + def removeCIX( self ): - self.archiver.removeArchiveFile( self.ci_xml_filename ) + return self.archiver.removeArchiveFile( self.ci_xml_filename ) def hasCIX(self): if not self.seemsToBeAComicArchive(): diff --git a/comictagger.py b/comictagger.py index c9107e6..d8be78b 100755 --- a/comictagger.py +++ b/comictagger.py @@ -27,6 +27,7 @@ import traceback import time from pprint import pprint import json +import platform try: qt_available = True @@ -123,8 +124,10 @@ def process_file_cli( filename, opts, settings ): if opts.data_style == MetaDataStyle.CIX: if cix: if not opts.dryrun: - ca.removeCIX() - print "Removed ComicRack tags." + if not ca.removeCIX(): + print "Tag removal seemed to fail!" + else: + print "Removed ComicRack tags." else: print "dry-run. ComicRack tags not removed" else: @@ -133,8 +136,10 @@ def process_file_cli( filename, opts, settings ): if opts.data_style == MetaDataStyle.CBI: if cbi: if not opts.dryrun: - ca.removeCBI() - print "Removed ComicBookLover tags." + if not ca.removeCBI(): + print "Tag removal seemed to fail!" + else: + print "Removed ComicBookLover tags." else: print "dry-run. ComicBookLover tags not removed" else: @@ -224,7 +229,10 @@ def process_file_cli( filename, opts, settings ): if not opts.dryrun: # write out the new data - ca.writeMetadata( md, opts.data_style ) + if not ca.writeMetadata( md, opts.data_style ): + print "The tag save seemed to fail!" + else: + print "Save complete." else: print "dry-run option was set, so nothing was written, but here is the final set of tags:" print u"{0}".format(md) @@ -265,7 +273,7 @@ def process_file_cli( filename, opts, settings ): new_name += " v{0}".format( md.volume ) if md.issue is not None: - new_name += " #{0}".format( md.issue ) + new_name += " #{:03d}".format( int(md.issue) ) else: print "Can't rename without issue number" return @@ -276,7 +284,7 @@ def process_file_cli( filename, opts, settings ): if md.year is not None: new_name += " ({0})".format( md.year ) - if ca.isZip: + if ca.isZip(): new_name += ".cbz" elif ca.isRar(): new_name += ".cbr" @@ -323,16 +331,20 @@ def main(): app = QtGui.QApplication(sys.argv) - img = QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/tags.png' )) - splash = QtGui.QSplashScreen(img) - splash.show() - splash.raise_() - app.processEvents() - + if platform.system() != "Linux": + img = QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/tags.png' )) + splash = QtGui.QSplashScreen(img) + splash.show() + splash.raise_() + app.processEvents() + try: tagger_window = TaggerWindow( opts.filename, settings ) tagger_window.show() - splash.finish( tagger_window ) + + if platform.system() != "Linux": + splash.finish( tagger_window ) + sys.exit(app.exec_()) except Exception, e: QtGui.QMessageBox.critical(QtGui.QMainWindow(), "Error", "Unhandled exception in app:\n" + traceback.format_exc() ) diff --git a/taggerwindow.py b/taggerwindow.py index 386ccea..0d361ca 100644 --- a/taggerwindow.py +++ b/taggerwindow.py @@ -693,7 +693,6 @@ class TaggerWindow( QtGui.QMainWindow): dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.ExistingFile) - print "last opened folder=", self.settings.last_opened_folder if self.settings.last_opened_folder is not None: dialog.setDirectory( self.settings.last_opened_folder ) #dialog.setFileMode(QtGui.QFileDialog.Directory ) @@ -803,13 +802,16 @@ class TaggerWindow( QtGui.QMainWindow): if reply == QtGui.QMessageBox.Yes: QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) self.formToMetadata() - self.comic_archive.writeMetadata( self.metadata, self.data_style ) - self.clearDirtyFlag() - self.updateInfoBox() - QtGui.QApplication.restoreOverrideCursor() - QtGui.QMessageBox.information(self, self.tr("Yeah!"), self.tr("File written.")) - + success = self.comic_archive.writeMetadata( self.metadata, self.data_style ) + QtGui.QApplication.restoreOverrideCursor() + + if not success: + QtGui.QMessageBox.warning(self, self.tr("Save failed"), self.tr("The tag save operation seemed to fail!")) + else: + self.clearDirtyFlag() + self.updateInfoBox() + #QtGui.QMessageBox.information(self, self.tr("Yeah!"), self.tr("File written.")) else: QtGui.QMessageBox.information(self, self.tr("Whoops!"), self.tr("No data to commit!")) @@ -1123,8 +1125,10 @@ class TaggerWindow( QtGui.QMainWindow): if reply == QtGui.QMessageBox.Yes: path = self.comic_archive.path - self.comic_archive.removeMetadata( style ) - self.updateInfoBox() + if not self.comic_archive.removeMetadata( style ): + QtGui.QMessageBox.warning(self, self.tr("Remove failed"), self.tr("The tag removal operation seemed to fail!")) + else: + self.updateInfoBox() def reloadAuto( self ):