def autoSelect(self): if self.comic_archive is None: QtGui.QMessageBox.information(self, "Auto-Select", "You need to load a comic first!") return if self.issue_number is None or self.issue_number == "": QtGui.QMessageBox.information( self, "Auto-Select", "Can't auto-select without an issue number (yet!)") return self.iddialog = IDProgressWindow(self) self.iddialog.setModal(True) self.iddialog.rejected.connect(self.identifyCancel) self.iddialog.show() self.ii = IssueIdentifier(self.comic_archive, self.settings) md = GenericMetadata() md.series = self.series_name md.issue = self.issue_number md.year = self.year md.issueCount = self.issue_count self.ii.setAdditionalMetadata(md) self.ii.onlyUseAdditionalMetaData = True self.ii.cover_page_index = int(self.cover_index_list[0]) self.id_thread = IdentifyThread(self.ii) self.id_thread.identifyComplete.connect(self.identifyComplete) self.id_thread.identifyLogMsg.connect(self.logIDOutput) self.id_thread.identifyProgress.connect(self.identifyProgress) self.id_thread.start() self.iddialog.exec_()
def autoSelect(self): if self.comic_archive is None: QtGui.QMessageBox.information( self, "Auto-Select", "You need to load a comic first!") return if self.issue_number is None or self.issue_number == "": QtGui.QMessageBox.information( self, "Auto-Select", "Can't auto-select without an issue number (yet!)") return self.iddialog = IDProgressWindow(self) self.iddialog.setModal(True) self.iddialog.rejected.connect(self.identifyCancel) self.iddialog.show() self.ii = IssueIdentifier(self.comic_archive, self.settings) md = GenericMetadata() md.series = self.series_name md.issue = self.issue_number md.year = self.year md.issueCount = self.issue_count self.ii.setAdditionalMetadata(md) self.ii.onlyUseAdditionalMetaData = True self.ii.cover_page_index = int(self.cover_index_list[0]) self.id_thread = IdentifyThread(self.ii) self.id_thread.identifyComplete.connect(self.identifyComplete) self.id_thread.identifyLogMsg.connect(self.logIDOutput) self.id_thread.identifyProgress.connect(self.identifyProgress) self.id_thread.start() self.iddialog.exec_()
def myoutput( text ): if opts.verbose: IssueIdentifier.defaultWriteOutput( text )
def process_file_cli( filename, opts, settings, match_results ): batch_mode = len( opts.file_list ) > 1 ca = ComicArchive(filename, settings.rar_exe_path) if not os.path.lexists( filename ): print "Cannot find "+ filename return if not ca.seemsToBeAComicArchive(): print "Sorry, but "+ filename + " is not a comic archive!" return #if not ca.isWritableForStyle( opts.data_style ) and ( opts.delete_tags or opts.save_tags or opts.rename_file ): if not ca.isWritable( ) and ( opts.delete_tags or opts.copy_tags or opts.save_tags or opts.rename_file ): print "This archive is not writable for that tag type" return has = [ False, False, False ] if ca.hasCIX(): has[ MetaDataStyle.CIX ] = True if ca.hasCBI(): has[ MetaDataStyle.CBI ] = True if ca.hasCoMet(): has[ MetaDataStyle.COMET ] = True if opts.print_tags: if opts.data_style is None: page_count = ca.getNumberOfPages() brief = "" if batch_mode: brief = u"{0}: ".format(filename) if ca.isZip(): brief += "ZIP archive " elif ca.isRar(): brief += "RAR archive " elif ca.isFolder(): brief += "Folder archive " brief += "({0: >3} pages)".format(page_count) brief += " tags:[ " if not ( has[ MetaDataStyle.CBI ] or has[ MetaDataStyle.CIX ] or has[ MetaDataStyle.COMET ] ): brief += "none " else: if has[ MetaDataStyle.CBI ]: brief += "CBL " if has[ MetaDataStyle.CIX ]: brief += "CR " if has[ MetaDataStyle.COMET ]: brief += "CoMet " brief += "]" print brief if opts.terse: return print if opts.data_style is None or opts.data_style == MetaDataStyle.CIX: if has[ MetaDataStyle.CIX ]: print "------ComicRack tags--------" if opts.raw: print u"{0}".format(unicode(ca.readRawCIX(), errors='ignore')) else: print u"{0}".format(ca.readCIX()) if opts.data_style is None or opts.data_style == MetaDataStyle.CBI: if has[ MetaDataStyle.CBI ]: print "------ComicBookLover tags--------" if opts.raw: pprint(json.loads(ca.readRawCBI())) else: print u"{0}".format(ca.readCBI()) if opts.data_style is None or opts.data_style == MetaDataStyle.COMET: if has[ MetaDataStyle.COMET ]: print "------CoMet tags--------" if opts.raw: print u"{0}".format(ca.readRawCoMet()) else: print u"{0}".format(ca.readCoMet()) elif opts.delete_tags: style_name = MetaDataStyle.name[ opts.data_style ] if has[ opts.data_style ]: if not opts.dryrun: if not ca.removeMetadata( opts.data_style ): print u"{0}: Tag removal seemed to fail!".format( filename ) else: print u"{0}: Removed {1} tags.".format( filename, style_name ) else: print u"{0}: dry-run. {1} tags not removed".format( filename, style_name ) else: print u"{0}: This archive doesn't have {1} tags to remove.".format( filename, style_name ) elif opts.copy_tags: dst_style_name = MetaDataStyle.name[ opts.data_style ] if opts.no_overwrite and has[ opts.data_style ]: print u"{0}: Already has {1} tags. Not overwriting.".format(filename, dst_style_name) return if opts.copy_source == opts.data_style: print u"{0}: Destination and source are same: {1}. Nothing to do.".format(filename, dst_style_name) return src_style_name = MetaDataStyle.name[ opts.copy_source ] if has[ opts.copy_source ]: if not opts.dryrun: md = ca.readMetadata( opts.copy_source ) if settings.apply_cbl_transform_on_bulk_operation and opts.data_style == MetaDataStyle.CBI: md = CBLTransformer( md, settings ).apply() if not ca.writeMetadata( md, opts.data_style ): print u"{0}: Tag copy seemed to fail!".format( filename ) else: print u"{0}: Copied {1} tags to {2} .".format( filename, src_style_name, dst_style_name ) else: print u"{0}: dry-run. {1} tags not copied".format( filename, src_style_name ) else: print u"{0}: This archive doesn't have {1} tags to copy.".format( filename, src_style_name ) elif opts.save_tags: if opts.no_overwrite and has[ opts.data_style ]: print u"{0}: Already has {1} tags. Not overwriting.".format(filename, MetaDataStyle.name[ opts.data_style ]) return if batch_mode: print u"Processing {0}...".format(filename) md = create_local_metadata( opts, ca, has[ opts.data_style ] ) if md.issue is None or md.issue == "": if opts.assume_issue_is_one_if_not_set: md.issue = "1" # now, search online if opts.search_online: if opts.issue_id is not None: # we were given the actual ID to search with try: comicVine = ComicVineTalker() comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit cv_md = comicVine.fetchIssueDataByIssueID( opts.issue_id, settings ) except ComicVineTalkerException: print "Network error while getting issue details. Save aborted" match_results.fetchDataFailures.append(filename) return if cv_md is None: print "No match for ID {0} was found.".format(opts.issue_id) match_results.noMatches.append(filename) return if settings.apply_cbl_transform_on_cv_import: cv_md = CBLTransformer( cv_md, settings ).apply() else: ii = IssueIdentifier( ca, settings ) if md is None or md.isEmpty: print "No metadata given to search online with!" match_results.noMatches.append(filename) return def myoutput( text ): if opts.verbose: IssueIdentifier.defaultWriteOutput( text ) # use our overlayed MD struct to search ii.setAdditionalMetadata( md ) ii.onlyUseAdditionalMetaData = True ii.waitAndRetryOnRateLimit = opts.wait_and_retry_on_rate_limit ii.setOutputFunction( myoutput ) ii.cover_page_index = md.getCoverPageIndexList()[0] matches = ii.search() result = ii.search_result found_match = False choices = False low_confidence = False if result == ii.ResultNoMatches: pass elif result == ii.ResultFoundMatchButBadCoverScore: low_confidence = True found_match = True elif result == ii.ResultFoundMatchButNotFirstPage : found_match = True elif result == ii.ResultMultipleMatchesWithBadImageScores: low_confidence = True choices = True elif result == ii.ResultOneGoodMatch: found_match = True elif result == ii.ResultMultipleGoodMatches: choices = True if choices: if low_confidence: print "Online search: Multiple low confidence matches. Save aborted" match_results.lowConfidenceMatches.append(MultipleMatch(filename,matches)) return else: print "Online search: Multiple good matches. Save aborted" match_results.multipleMatches.append(MultipleMatch(filename,matches)) return if low_confidence and opts.abortOnLowConfidence: print "Online search: Low confidence match. Save aborted" match_results.lowConfidenceMatches.append(MultipleMatch(filename,matches)) return if not found_match: print "Online search: No match found. Save aborted" match_results.noMatches.append(filename) return # we got here, so we have a single match # now get the particular issue data cv_md = actual_issue_data_fetch(matches[0], settings, opts) if cv_md is None: match_results.fetchDataFailures.append(filename) return md.overlay( cv_md ) # ok, done building our metadata. time to save if not actual_metadata_save( ca, opts, md ): match_results.writeFailures.append(filename) else: match_results.goodMatches.append(filename) elif opts.rename_file: msg_hdr = "" if batch_mode: msg_hdr = u"{0}: ".format(filename) if opts.data_style is not None: use_tags = has[ opts.data_style ] else: use_tags = False md = create_local_metadata( opts, ca, use_tags ) if md.series is None: print msg_hdr + "Can't rename without series name" return new_ext = None # default if settings.rename_extension_based_on_archive: if ca.isZip(): new_ext = ".cbz" elif ca.isRar(): new_ext = ".cbr" renamer = FileRenamer( md ) renamer.setTemplate( settings.rename_template ) renamer.setIssueZeroPadding( settings.rename_issue_number_padding ) renamer.setSmartCleanup( settings.rename_use_smart_string_cleanup ) new_name = renamer.determineName( filename, ext=new_ext ) if new_name == os.path.basename(filename): print msg_hdr + "Filename is already good!" return folder = os.path.dirname( os.path.abspath( filename ) ) new_abs_path = utils.unique_file( os.path.join( folder, new_name ) ) suffix = "" if not opts.dryrun: # rename the file os.rename( filename, new_abs_path ) else: suffix = " (dry-run, no change)" print u"renamed '{0}' -> '{1}' {2}".format(os.path.basename(filename), new_name, suffix) elif opts.export_to_zip: msg_hdr = "" if batch_mode: msg_hdr = u"{0}: ".format(filename) if not ca.isRar(): print msg_hdr + "Archive is not a RAR." return rar_file = os.path.abspath( os.path.abspath( filename ) ) new_file = os.path.splitext(rar_file)[0] + ".cbz" if opts.abort_export_on_conflict and os.path.lexists( new_file ): print msg_hdr + "{0} already exists in the that folder.".format(os.path.split(new_file)[1]) return new_file = utils.unique_file( os.path.join( new_file ) ) delete_success = False export_success = False if not opts.dryrun: if ca.exportAsZip( new_file ): export_success = True if opts.delete_rar_after_export: try: os.unlink( rar_file ) except: print msg_hdr + "Error deleting original RAR after export" delete_success = False else: delete_success = True else: # last export failed, so remove the zip, if it exists if os.path.lexists( new_file ): os.remove( new_file ) else: msg = msg_hdr + u"Dry-run: Would try to create {0}".format(os.path.split(new_file)[1]) if opts.delete_rar_after_export: msg += u" and delete orginal." print msg return msg = msg_hdr if export_success: msg += u"Archive exported successfully to: {0}".format( os.path.split(new_file)[1] ) if opts.delete_rar_after_export and delete_success: msg += u" (Original deleted) " else: msg += u"Archive failed to export!" print msg
def myoutput(text): if opts.verbose: IssueIdentifier.defaultWriteOutput(text)
def process_file_cli(filename, opts, settings, match_results): batch_mode = len(opts.file_list) > 1 ca = ComicArchive(filename, settings.rar_exe_path) if not os.path.lexists(filename): print "Cannot find " + filename return if not ca.seemsToBeAComicArchive(): print "Sorry, but " + filename + " is not a comic archive!" return #if not ca.isWritableForStyle( opts.data_style ) and ( opts.delete_tags or opts.save_tags or opts.rename_file ): if not ca.isWritable() and (opts.delete_tags or opts.copy_tags or opts.save_tags or opts.rename_file): print "This archive is not writable for that tag type" return has = [False, False, False] if ca.hasCIX(): has[MetaDataStyle.CIX] = True if ca.hasCBI(): has[MetaDataStyle.CBI] = True if ca.hasCoMet(): has[MetaDataStyle.COMET] = True if opts.print_tags: if opts.data_style is None: page_count = ca.getNumberOfPages() brief = "" if batch_mode: brief = u"{0}: ".format(filename) if ca.isZip(): brief += "ZIP archive " elif ca.isRar(): brief += "RAR archive " elif ca.isFolder(): brief += "Folder archive " brief += "({0: >3} pages)".format(page_count) brief += " tags:[ " if not (has[MetaDataStyle.CBI] or has[MetaDataStyle.CIX] or has[MetaDataStyle.COMET]): brief += "none " else: if has[MetaDataStyle.CBI]: brief += "CBL " if has[MetaDataStyle.CIX]: brief += "CR " if has[MetaDataStyle.COMET]: brief += "CoMet " brief += "]" print brief if opts.terse: return print if opts.data_style is None or opts.data_style == MetaDataStyle.CIX: if has[MetaDataStyle.CIX]: print "------ComicRack tags--------" if opts.raw: print u"{0}".format( unicode(ca.readRawCIX(), errors='ignore')) else: print u"{0}".format(ca.readCIX()) if opts.data_style is None or opts.data_style == MetaDataStyle.CBI: if has[MetaDataStyle.CBI]: print "------ComicBookLover tags--------" if opts.raw: pprint(json.loads(ca.readRawCBI())) else: print u"{0}".format(ca.readCBI()) if opts.data_style is None or opts.data_style == MetaDataStyle.COMET: if has[MetaDataStyle.COMET]: print "------CoMet tags--------" if opts.raw: print u"{0}".format(ca.readRawCoMet()) else: print u"{0}".format(ca.readCoMet()) elif opts.delete_tags: style_name = MetaDataStyle.name[opts.data_style] if has[opts.data_style]: if not opts.dryrun: if not ca.removeMetadata(opts.data_style): print u"{0}: Tag removal seemed to fail!".format(filename) else: print u"{0}: Removed {1} tags.".format( filename, style_name) else: print u"{0}: dry-run. {1} tags not removed".format( filename, style_name) else: print u"{0}: This archive doesn't have {1} tags to remove.".format( filename, style_name) elif opts.copy_tags: dst_style_name = MetaDataStyle.name[opts.data_style] if opts.no_overwrite and has[opts.data_style]: print u"{0}: Already has {1} tags. Not overwriting.".format( filename, dst_style_name) return if opts.copy_source == opts.data_style: print u"{0}: Destination and source are same: {1}. Nothing to do.".format( filename, dst_style_name) return src_style_name = MetaDataStyle.name[opts.copy_source] if has[opts.copy_source]: if not opts.dryrun: md = ca.readMetadata(opts.copy_source) if settings.apply_cbl_transform_on_bulk_operation and opts.data_style == MetaDataStyle.CBI: md = CBLTransformer(md, settings).apply() if not ca.writeMetadata(md, opts.data_style): print u"{0}: Tag copy seemed to fail!".format(filename) else: print u"{0}: Copied {1} tags to {2} .".format( filename, src_style_name, dst_style_name) else: print u"{0}: dry-run. {1} tags not copied".format( filename, src_style_name) else: print u"{0}: This archive doesn't have {1} tags to copy.".format( filename, src_style_name) elif opts.save_tags: if opts.no_overwrite and has[opts.data_style]: print u"{0}: Already has {1} tags. Not overwriting.".format( filename, MetaDataStyle.name[opts.data_style]) return if batch_mode: print u"Processing {0}...".format(filename) md = create_local_metadata(opts, ca, has[opts.data_style]) if md.issue is None or md.issue == "": if opts.assume_issue_is_one_if_not_set: md.issue = "1" # now, search online if opts.search_online: if opts.issue_id is not None: # we were given the actual ID to search with try: comicVine = ComicVineTalker() comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit cv_md = comicVine.fetchIssueDataByIssueID( opts.issue_id, settings) except ComicVineTalkerException: print "Network error while getting issue details. Save aborted" match_results.fetchDataFailures.append(filename) return if cv_md is None: print "No match for ID {0} was found.".format( opts.issue_id) match_results.noMatches.append(filename) return if settings.apply_cbl_transform_on_cv_import: cv_md = CBLTransformer(cv_md, settings).apply() else: ii = IssueIdentifier(ca, settings) if md is None or md.isEmpty: print "No metadata given to search online with!" match_results.noMatches.append(filename) return def myoutput(text): if opts.verbose: IssueIdentifier.defaultWriteOutput(text) # use our overlayed MD struct to search ii.setAdditionalMetadata(md) ii.onlyUseAdditionalMetaData = True ii.waitAndRetryOnRateLimit = opts.wait_and_retry_on_rate_limit ii.setOutputFunction(myoutput) ii.cover_page_index = md.getCoverPageIndexList()[0] matches = ii.search() result = ii.search_result found_match = False choices = False low_confidence = False if result == ii.ResultNoMatches: pass elif result == ii.ResultFoundMatchButBadCoverScore: low_confidence = True found_match = True elif result == ii.ResultFoundMatchButNotFirstPage: found_match = True elif result == ii.ResultMultipleMatchesWithBadImageScores: low_confidence = True choices = True elif result == ii.ResultOneGoodMatch: found_match = True elif result == ii.ResultMultipleGoodMatches: choices = True if choices: if low_confidence: print "Online search: Multiple low confidence matches. Save aborted" match_results.lowConfidenceMatches.append( MultipleMatch(filename, matches)) return else: print "Online search: Multiple good matches. Save aborted" match_results.multipleMatches.append( MultipleMatch(filename, matches)) return if low_confidence and opts.abortOnLowConfidence: print "Online search: Low confidence match. Save aborted" match_results.lowConfidenceMatches.append( MultipleMatch(filename, matches)) return if not found_match: print "Online search: No match found. Save aborted" match_results.noMatches.append(filename) return # we got here, so we have a single match # now get the particular issue data cv_md = actual_issue_data_fetch(matches[0], settings, opts) if cv_md is None: match_results.fetchDataFailures.append(filename) return md.overlay(cv_md) # ok, done building our metadata. time to save if not actual_metadata_save(ca, opts, md): match_results.writeFailures.append(filename) else: match_results.goodMatches.append(filename) elif opts.rename_file: msg_hdr = "" if batch_mode: msg_hdr = u"{0}: ".format(filename) if opts.data_style is not None: use_tags = has[opts.data_style] else: use_tags = False md = create_local_metadata(opts, ca, use_tags) if md.series is None: print msg_hdr + "Can't rename without series name" return new_ext = None # default if settings.rename_extension_based_on_archive: if ca.isZip(): new_ext = ".cbz" elif ca.isRar(): new_ext = ".cbr" renamer = FileRenamer(md) renamer.setTemplate(settings.rename_template) renamer.setIssueZeroPadding(settings.rename_issue_number_padding) renamer.setSmartCleanup(settings.rename_use_smart_string_cleanup) new_name = renamer.determineName(filename, ext=new_ext) if new_name == os.path.basename(filename): print msg_hdr + "Filename is already good!" return folder = os.path.dirname(os.path.abspath(filename)) new_abs_path = utils.unique_file(os.path.join(folder, new_name)) suffix = "" if not opts.dryrun: # rename the file os.rename(filename, new_abs_path) else: suffix = " (dry-run, no change)" print u"renamed '{0}' -> '{1}' {2}".format(os.path.basename(filename), new_name, suffix) elif opts.export_to_zip: msg_hdr = "" if batch_mode: msg_hdr = u"{0}: ".format(filename) if not ca.isRar(): print msg_hdr + "Archive is not a RAR." return rar_file = os.path.abspath(os.path.abspath(filename)) new_file = os.path.splitext(rar_file)[0] + ".cbz" if opts.abort_export_on_conflict and os.path.lexists(new_file): print msg_hdr + "{0} already exists in the that folder.".format( os.path.split(new_file)[1]) return new_file = utils.unique_file(os.path.join(new_file)) delete_success = False export_success = False if not opts.dryrun: if ca.exportAsZip(new_file): export_success = True if opts.delete_rar_after_export: try: os.unlink(rar_file) except: print msg_hdr + "Error deleting original RAR after export" delete_success = False else: delete_success = True else: # last export failed, so remove the zip, if it exists if os.path.lexists(new_file): os.remove(new_file) else: msg = msg_hdr + u"Dry-run: Would try to create {0}".format( os.path.split(new_file)[1]) if opts.delete_rar_after_export: msg += u" and delete orginal." print msg return msg = msg_hdr if export_success: msg += u"Archive exported successfully to: {0}".format( os.path.split(new_file)[1]) if opts.delete_rar_after_export and delete_success: msg += u" (Original deleted) " else: msg += u"Archive failed to export!" print msg
class VolumeSelectionWindow(QtGui.QDialog): def __init__(self, parent, series_name, issue_number, year, issue_count, cover_index_list, comic_archive, settings, autoselect=False): super(VolumeSelectionWindow, self).__init__(parent) uic.loadUi( ComicTaggerSettings.getUIFile('volumeselectionwindow.ui'), self) self.imageWidget = CoverImageWidget( self.imageContainer, CoverImageWidget.URLMode) gridlayout = QtGui.QGridLayout(self.imageContainer) gridlayout.addWidget(self.imageWidget) gridlayout.setContentsMargins(0, 0, 0, 0) reduceWidgetFontSize(self.teDetails, 1) reduceWidgetFontSize(self.twList) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowMaximizeButtonHint) self.settings = settings self.series_name = series_name self.issue_number = issue_number self.year = year self.issue_count = issue_count self.volume_id = 0 self.comic_archive = comic_archive self.immediate_autoselect = autoselect self.cover_index_list = cover_index_list self.cv_search_results = None self.twList.resizeColumnsToContents() self.twList.currentItemChanged.connect(self.currentItemChanged) self.twList.cellDoubleClicked.connect(self.cellDoubleClicked) self.btnRequery.clicked.connect(self.requery) self.btnIssues.clicked.connect(self.showIssues) self.btnAutoSelect.clicked.connect(self.autoSelect) self.updateButtons() self.performQuery() self.twList.selectRow(0) def updateButtons(self): if self.cv_search_results is not None and len( self.cv_search_results) > 0: enabled = True else: enabled = False self.btnRequery.setEnabled(enabled) self.btnIssues.setEnabled(enabled) self.btnAutoSelect.setEnabled(enabled) self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(enabled) def requery(self,): self.performQuery(refresh=True) self.twList.selectRow(0) def autoSelect(self): if self.comic_archive is None: QtGui.QMessageBox.information( self, "Auto-Select", "You need to load a comic first!") return if self.issue_number is None or self.issue_number == "": QtGui.QMessageBox.information( self, "Auto-Select", "Can't auto-select without an issue number (yet!)") return self.iddialog = IDProgressWindow(self) self.iddialog.setModal(True) self.iddialog.rejected.connect(self.identifyCancel) self.iddialog.show() self.ii = IssueIdentifier(self.comic_archive, self.settings) md = GenericMetadata() md.series = self.series_name md.issue = self.issue_number md.year = self.year md.issueCount = self.issue_count self.ii.setAdditionalMetadata(md) self.ii.onlyUseAdditionalMetaData = True self.ii.cover_page_index = int(self.cover_index_list[0]) self.id_thread = IdentifyThread(self.ii) self.id_thread.identifyComplete.connect(self.identifyComplete) self.id_thread.identifyLogMsg.connect(self.logIDOutput) self.id_thread.identifyProgress.connect(self.identifyProgress) self.id_thread.start() self.iddialog.exec_() def logIDOutput(self, text): print unicode(text), self.iddialog.textEdit.ensureCursorVisible() self.iddialog.textEdit.insertPlainText(text) def identifyProgress(self, cur, total): self.iddialog.progressBar.setMaximum(total) self.iddialog.progressBar.setValue(cur) def identifyCancel(self): self.ii.cancel = True def identifyComplete(self): matches = self.ii.match_list result = self.ii.search_result match_index = 0 found_match = None choices = False if result == self.ii.ResultNoMatches: QtGui.QMessageBox.information( self, "Auto-Select Result", " No matches found :-(") elif result == self.ii.ResultFoundMatchButBadCoverScore: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found a match, but cover doesn't seem the same. Verify before commiting!") found_match = matches[0] elif result == self.ii.ResultFoundMatchButNotFirstPage: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found a match, but not with the first page of the archive.") found_match = matches[0] elif result == self.ii.ResultMultipleMatchesWithBadImageScores: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found some possibilities, but no confidence. Proceed manually.") choices = True elif result == self.ii.ResultOneGoodMatch: found_match = matches[0] elif result == self.ii.ResultMultipleGoodMatches: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found multiple likely matches. Please select.") choices = True if choices: selector = MatchSelectionWindow(self, matches, self.comic_archive) selector.setModal(True) selector.exec_() if selector.result(): # we should now have a list index found_match = selector.currentMatch() if found_match is not None: self.iddialog.accept() self.volume_id = found_match['volume_id'] self.issue_number = found_match['issue_number'] self.selectByID() self.showIssues() def showIssues(self): selector = IssueSelectionWindow( self, self.settings, self.volume_id, self.issue_number) title = "" for record in self.cv_search_results: if record['id'] == self.volume_id: title = record['name'] title += " (" + unicode(record['start_year']) + ")" title += " - " break selector.setWindowTitle(title + "Select Issue") selector.setModal(True) selector.exec_() if selector.result(): # we should now have a volume ID self.issue_number = selector.issue_number self.accept() return def selectByID(self): for r in range(0, self.twList.rowCount()): volume_id, b = self.twList.item( r, 0).data(QtCore.Qt.UserRole).toInt() if (volume_id == self.volume_id): self.twList.selectRow(r) break def performQuery(self, refresh=False): self.progdialog = QtGui.QProgressDialog( "Searching Online", "Cancel", 0, 100, self) self.progdialog.setWindowTitle("Online Search") self.progdialog.canceled.connect(self.searchCanceled) self.progdialog.setModal(True) self.search_thread = SearchThread(self.series_name, refresh) self.search_thread.searchComplete.connect(self.searchComplete) self.search_thread.progressUpdate.connect(self.searchProgressUpdate) self.search_thread.start() # QtCore.QCoreApplication.processEvents() self.progdialog.exec_() def searchCanceled(self): print("query cancelled") self.search_thread.searchComplete.disconnect(self.searchComplete) self.search_thread.progressUpdate.disconnect(self.searchProgressUpdate) self.progdialog.canceled.disconnect(self.searchCanceled) self.progdialog.reject() QtCore.QTimer.singleShot(200, self.closeMe) def closeMe(self): print("closeme") self.reject() def searchProgressUpdate(self, current, total): self.progdialog.setMaximum(total) self.progdialog.setValue(current) def searchComplete(self): self.progdialog.accept() if self.search_thread.cv_error: if self.search_thread.error_code == ComicVineTalkerException.RateLimit: QtGui.QMessageBox.critical( self, self.tr("Comic Vine Error"), ComicVineTalker.getRateLimitMessage()) else: QtGui.QMessageBox.critical( self, self.tr("Network Issue"), self.tr("Could not connect to Comic Vine to search for series!")) return self.cv_search_results = self.search_thread.cv_search_results self.updateButtons() self.twList.setSortingEnabled(False) while self.twList.rowCount() > 0: self.twList.removeRow(0) row = 0 for record in self.cv_search_results: self.twList.insertRow(row) item_text = record['name'] item = QtGui.QTableWidgetItem(item_text) item.setData(QtCore.Qt.ToolTipRole, item_text) item.setData(QtCore.Qt.UserRole, record['id']) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 0, item) item_text = str(record['start_year']) item = QtGui.QTableWidgetItem(item_text) item.setData(QtCore.Qt.ToolTipRole, item_text) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 1, item) item_text = record['count_of_issues'] item = QtGui.QTableWidgetItem(item_text) item.setData(QtCore.Qt.ToolTipRole, item_text) item.setData(QtCore.Qt.DisplayRole, record['count_of_issues']) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 2, item) if record['publisher'] is not None: item_text = record['publisher']['name'] item.setData(QtCore.Qt.ToolTipRole, item_text) item = QtGui.QTableWidgetItem(item_text) item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 3, item) row += 1 self.twList.resizeColumnsToContents() self.twList.setSortingEnabled(True) self.twList.sortItems(2, QtCore.Qt.DescendingOrder) self.twList.selectRow(0) self.twList.resizeColumnsToContents() if len(self.cv_search_results) == 0: QtCore.QCoreApplication.processEvents() QtGui.QMessageBox.information( self, "Search Result", "No matches found!") if self.immediate_autoselect and len(self.cv_search_results) > 0: # defer the immediate autoselect so this dialog has time to pop up QtCore.QCoreApplication.processEvents() QtCore.QTimer.singleShot(10, self.doImmediateAutoselect) def doImmediateAutoselect(self): self.immediate_autoselect = False self.autoSelect() def cellDoubleClicked(self, r, c): self.showIssues() def currentItemChanged(self, curr, prev): if curr is None: return if prev is not None and prev.row() == curr.row(): return self.volume_id, b = self.twList.item( curr.row(), 0).data(QtCore.Qt.UserRole).toInt() # list selection was changed, update the info on the volume for record in self.cv_search_results: if record['id'] == self.volume_id: if record['description'] is None: self.teDetails.setText("") else: self.teDetails.setText(record['description']) self.imageWidget.setURL(record['image']['super_url']) break
class VolumeSelectionWindow(QtGui.QDialog): def __init__(self, parent, series_name, issue_number, year, issue_count, cover_index_list, comic_archive, settings, autoselect=False): super(VolumeSelectionWindow, self).__init__(parent) uic.loadUi(ComicTaggerSettings.getUIFile('volumeselectionwindow.ui'), self) self.imageWidget = CoverImageWidget(self.imageContainer, CoverImageWidget.URLMode) gridlayout = QtGui.QGridLayout(self.imageContainer) gridlayout.addWidget(self.imageWidget) gridlayout.setContentsMargins(0, 0, 0, 0) reduceWidgetFontSize(self.teDetails, 1) reduceWidgetFontSize(self.twList) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowMaximizeButtonHint) self.settings = settings self.series_name = series_name self.issue_number = issue_number self.year = year self.issue_count = issue_count self.volume_id = 0 self.comic_archive = comic_archive self.immediate_autoselect = autoselect self.cover_index_list = cover_index_list self.cv_search_results = None self.twList.resizeColumnsToContents() self.twList.currentItemChanged.connect(self.currentItemChanged) self.twList.cellDoubleClicked.connect(self.cellDoubleClicked) self.btnRequery.clicked.connect(self.requery) self.btnIssues.clicked.connect(self.showIssues) self.btnAutoSelect.clicked.connect(self.autoSelect) self.updateButtons() self.performQuery() self.twList.selectRow(0) def updateButtons(self): if self.cv_search_results is not None and len( self.cv_search_results) > 0: enabled = True else: enabled = False self.btnRequery.setEnabled(enabled) self.btnIssues.setEnabled(enabled) self.btnAutoSelect.setEnabled(enabled) self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(enabled) def requery(self, ): self.performQuery(refresh=True) self.twList.selectRow(0) def autoSelect(self): if self.comic_archive is None: QtGui.QMessageBox.information(self, "Auto-Select", "You need to load a comic first!") return if self.issue_number is None or self.issue_number == "": QtGui.QMessageBox.information( self, "Auto-Select", "Can't auto-select without an issue number (yet!)") return self.iddialog = IDProgressWindow(self) self.iddialog.setModal(True) self.iddialog.rejected.connect(self.identifyCancel) self.iddialog.show() self.ii = IssueIdentifier(self.comic_archive, self.settings) md = GenericMetadata() md.series = self.series_name md.issue = self.issue_number md.year = self.year md.issueCount = self.issue_count self.ii.setAdditionalMetadata(md) self.ii.onlyUseAdditionalMetaData = True self.ii.cover_page_index = int(self.cover_index_list[0]) self.id_thread = IdentifyThread(self.ii) self.id_thread.identifyComplete.connect(self.identifyComplete) self.id_thread.identifyLogMsg.connect(self.logIDOutput) self.id_thread.identifyProgress.connect(self.identifyProgress) self.id_thread.start() self.iddialog.exec_() def logIDOutput(self, text): print unicode(text), self.iddialog.textEdit.ensureCursorVisible() self.iddialog.textEdit.insertPlainText(text) def identifyProgress(self, cur, total): self.iddialog.progressBar.setMaximum(total) self.iddialog.progressBar.setValue(cur) def identifyCancel(self): self.ii.cancel = True def identifyComplete(self): matches = self.ii.match_list result = self.ii.search_result match_index = 0 found_match = None choices = False if result == self.ii.ResultNoMatches: QtGui.QMessageBox.information(self, "Auto-Select Result", " No matches found :-(") elif result == self.ii.ResultFoundMatchButBadCoverScore: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found a match, but cover doesn't seem the same. Verify before commiting!" ) found_match = matches[0] elif result == self.ii.ResultFoundMatchButNotFirstPage: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found a match, but not with the first page of the archive.") found_match = matches[0] elif result == self.ii.ResultMultipleMatchesWithBadImageScores: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found some possibilities, but no confidence. Proceed manually." ) choices = True elif result == self.ii.ResultOneGoodMatch: found_match = matches[0] elif result == self.ii.ResultMultipleGoodMatches: QtGui.QMessageBox.information( self, "Auto-Select Result", " Found multiple likely matches. Please select.") choices = True if choices: selector = MatchSelectionWindow(self, matches, self.comic_archive) selector.setModal(True) selector.exec_() if selector.result(): # we should now have a list index found_match = selector.currentMatch() if found_match is not None: self.iddialog.accept() self.volume_id = found_match['volume_id'] self.issue_number = found_match['issue_number'] self.selectByID() self.showIssues() def showIssues(self): selector = IssueSelectionWindow(self, self.settings, self.volume_id, self.issue_number) title = "" for record in self.cv_search_results: if record['id'] == self.volume_id: title = record['name'] title += " (" + unicode(record['start_year']) + ")" title += " - " break selector.setWindowTitle(title + "Select Issue") selector.setModal(True) selector.exec_() if selector.result(): # we should now have a volume ID self.issue_number = selector.issue_number self.accept() return def selectByID(self): for r in range(0, self.twList.rowCount()): volume_id, b = self.twList.item(r, 0).data( QtCore.Qt.UserRole).toInt() if (volume_id == self.volume_id): self.twList.selectRow(r) break def performQuery(self, refresh=False): self.progdialog = QtGui.QProgressDialog("Searching Online", "Cancel", 0, 100, self) self.progdialog.setWindowTitle("Online Search") self.progdialog.canceled.connect(self.searchCanceled) self.progdialog.setModal(True) self.search_thread = SearchThread(self.series_name, refresh) self.search_thread.searchComplete.connect(self.searchComplete) self.search_thread.progressUpdate.connect(self.searchProgressUpdate) self.search_thread.start() # QtCore.QCoreApplication.processEvents() self.progdialog.exec_() def searchCanceled(self): print("query cancelled") self.search_thread.searchComplete.disconnect(self.searchComplete) self.search_thread.progressUpdate.disconnect(self.searchProgressUpdate) self.progdialog.canceled.disconnect(self.searchCanceled) self.progdialog.reject() QtCore.QTimer.singleShot(200, self.closeMe) def closeMe(self): print("closeme") self.reject() def searchProgressUpdate(self, current, total): self.progdialog.setMaximum(total) self.progdialog.setValue(current) def searchComplete(self): self.progdialog.accept() if self.search_thread.cv_error: if self.search_thread.error_code == ComicVineTalkerException.RateLimit: QtGui.QMessageBox.critical( self, self.tr("Comic Vine Error"), ComicVineTalker.getRateLimitMessage()) else: QtGui.QMessageBox.critical( self, self.tr("Network Issue"), self.tr( "Could not connect to Comic Vine to search for series!" )) return self.cv_search_results = self.search_thread.cv_search_results self.updateButtons() self.twList.setSortingEnabled(False) while self.twList.rowCount() > 0: self.twList.removeRow(0) row = 0 for record in self.cv_search_results: self.twList.insertRow(row) item_text = record['name'] item = QtGui.QTableWidgetItem(item_text) item.setData(QtCore.Qt.ToolTipRole, item_text) item.setData(QtCore.Qt.UserRole, record['id']) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 0, item) item_text = str(record['start_year']) item = QtGui.QTableWidgetItem(item_text) item.setData(QtCore.Qt.ToolTipRole, item_text) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 1, item) item_text = record['count_of_issues'] item = QtGui.QTableWidgetItem(item_text) item.setData(QtCore.Qt.ToolTipRole, item_text) item.setData(QtCore.Qt.DisplayRole, record['count_of_issues']) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 2, item) if record['publisher'] is not None: item_text = record['publisher']['name'] item.setData(QtCore.Qt.ToolTipRole, item_text) item = QtGui.QTableWidgetItem(item_text) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.twList.setItem(row, 3, item) row += 1 self.twList.resizeColumnsToContents() self.twList.setSortingEnabled(True) self.twList.sortItems(2, QtCore.Qt.DescendingOrder) self.twList.selectRow(0) self.twList.resizeColumnsToContents() if len(self.cv_search_results) == 0: QtCore.QCoreApplication.processEvents() QtGui.QMessageBox.information(self, "Search Result", "No matches found!") if self.immediate_autoselect and len(self.cv_search_results) > 0: # defer the immediate autoselect so this dialog has time to pop up QtCore.QCoreApplication.processEvents() QtCore.QTimer.singleShot(10, self.doImmediateAutoselect) def doImmediateAutoselect(self): self.immediate_autoselect = False self.autoSelect() def cellDoubleClicked(self, r, c): self.showIssues() def currentItemChanged(self, curr, prev): if curr is None: return if prev is not None and prev.row() == curr.row(): return self.volume_id, b = self.twList.item(curr.row(), 0).data( QtCore.Qt.UserRole).toInt() # list selection was changed, update the info on the volume for record in self.cv_search_results: if record['id'] == self.volume_id: if record['description'] is None: self.teDetails.setText("") else: self.teDetails.setText(record['description']) self.imageWidget.setURL(record['image']['super_url']) break