From 221923607ac682e8df725af2c830ad7d87a1711f Mon Sep 17 00:00:00 2001 From: beville Date: Tue, 22 Jan 2013 04:09:08 +0000 Subject: [PATCH] Auto-Tag progress window added More auto-tag and other stuff git-svn-id: http://comictagger.googlecode.com/svn/trunk@322 6c5673fe-1810-88d6-992b-cd32ca31540c --- autotagprogresswindow.py | 60 ++++++++++++++++ autotagprogresswindow.ui | 152 +++++++++++++++++++++++++++++++++++++++ autotagstartwindow.py | 3 + autotagstartwindow.ui | 7 ++ comictagger.py | 2 +- filerenamer.py | 3 + fileselectionlist.ui | 29 +++++++- issueidentifier.py | 11 ++- renamewindow.py | 3 + settingswindow.ui | 2 +- taggerwindow.py | 81 ++++++++++++++------- todo.txt | 24 +++---- 12 files changed, 333 insertions(+), 44 deletions(-) create mode 100644 autotagprogresswindow.py create mode 100644 autotagprogresswindow.ui diff --git a/autotagprogresswindow.py b/autotagprogresswindow.py new file mode 100644 index 0000000..ad0b36b --- /dev/null +++ b/autotagprogresswindow.py @@ -0,0 +1,60 @@ +""" +A PyQT4 dialog to show ID log and progress +""" + +""" +Copyright 2012 Anthony Beville + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import sys +from PyQt4 import QtCore, QtGui, uic +import os +from settings import ComicTaggerSettings + + +class AutoTagProgressWindow(QtGui.QDialog): + + + def __init__(self, parent): + super(AutoTagProgressWindow, self).__init__(parent) + + uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'autotagprogresswindow.ui' ), self) + self.lblTest.setPixmap(QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/nocover.png' ))) + self.lblArchive.setPixmap(QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/nocover.png' ))) + self.isdone = False + + def setArchiveImage( self, img_data): + self.setCoverImage( img_data, self.lblArchive ) + + def setTestImage( self, img_data): + self.setCoverImage( img_data, self.lblTest ) + + def setCoverImage( self, img_data , label): + if img_data is not None: + img = QtGui.QImage() + img.loadFromData( img_data ) + label.setPixmap(QtGui.QPixmap(img)) + label.setScaledContents(True) + else: + label.setPixmap(QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/nocover.png' ))) + label.setScaledContents(True) + QtCore.QCoreApplication.processEvents() + QtCore.QCoreApplication.processEvents() + + def reject(self): + QtGui.QDialog.reject(self) + self.isdone = True + + \ No newline at end of file diff --git a/autotagprogresswindow.ui b/autotagprogresswindow.ui new file mode 100644 index 0000000..13cf566 --- /dev/null +++ b/autotagprogresswindow.ui @@ -0,0 +1,152 @@ + + + dialogIssueSelect + + + + 0 + 0 + 865 + 413 + + + + + 16777215 + 16777215 + + + + Issue Identification Progress + + + + + + + + 0 + + + false + + + + + + + + + + + + + + + Courier New + 75 + true + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + true + + + + + + + + + + 0 + 0 + + + + + 110 + 165 + + + + + 110 + 165 + + + + TextLabel + + + + + + + + 110 + 165 + + + + + 110 + 165 + + + + TextLabel + + + + + + + + + buttonBox + accepted() + dialogIssueSelect + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + dialogIssueSelect + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/autotagstartwindow.py b/autotagstartwindow.py index 3daca55..bfbe3df 100644 --- a/autotagstartwindow.py +++ b/autotagstartwindow.py @@ -38,12 +38,15 @@ class AutoTagStartWindow(QtGui.QDialog): self.settings = settings self.cbxNoAutoSaveOnLow.setCheckState( QtCore.Qt.Unchecked ) + self.cbxDontUseYear.setCheckState( QtCore.Qt.Unchecked ) self.noAutoSaveOnLow = False + self.dontUseYear = False def accept( self ): QtGui.QDialog.accept(self) self.noAutoSaveOnLow = self.cbxNoAutoSaveOnLow.isChecked() + self.dontUseYear = self.cbxDontUseYear.isChecked() \ No newline at end of file diff --git a/autotagstartwindow.ui b/autotagstartwindow.ui index f43489e..3b46aed 100644 --- a/autotagstartwindow.ui +++ b/autotagstartwindow.ui @@ -50,6 +50,13 @@ + + + + Don't use publication year in indentification process + + + diff --git a/comictagger.py b/comictagger.py index 5890320..04e6b4e 100755 --- a/comictagger.py +++ b/comictagger.py @@ -294,7 +294,7 @@ def process_file_cli( filename, opts, settings, match_results ): if not opts.dryrun: md = ca.readMetadata( opts.copy_source ) - if settings.apply_cbl_transform_on_bulk_operation: + 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 ): diff --git a/filerenamer.py b/filerenamer.py index 417002c..644fdd5 100644 --- a/filerenamer.py +++ b/filerenamer.py @@ -106,7 +106,10 @@ class FileRenamer: new_name += ext + # some tweaks to keep various filesystems happy new_name = new_name.replace("/", "-") + new_name = new_name.replace(":", "-") + return new_name diff --git a/fileselectionlist.ui b/fileselectionlist.ui index 1b69370..0770453 100644 --- a/fileselectionlist.ui +++ b/fileselectionlist.ui @@ -41,13 +41,19 @@ File + + File Name + + + AlignHCenter|AlignVCenter|AlignCenter + CR - + Has ComicRack Tags AlignHCenter|AlignVCenter|AlignCenter @@ -57,6 +63,9 @@ CBL + + Has ComicBookLover Tags + AlignHCenter|AlignVCenter|AlignCenter @@ -65,16 +74,34 @@ Type + + Archive Type + + + AlignHCenter|AlignVCenter|AlignCenter + R/O + + Read-Only + + + AlignHCenter|AlignVCenter|AlignCenter + Folder + + File Location + + + AlignHCenter|AlignVCenter|AlignCenter + diff --git a/issueidentifier.py b/issueidentifier.py index 2ad08a9..42e7874 100644 --- a/issueidentifier.py +++ b/issueidentifier.py @@ -72,6 +72,7 @@ class IssueIdentifier: self.additional_metadata = GenericMetadata() self.output_function = IssueIdentifier.defaultWriteOutput self.callback = None + self.coverUrlCallback = None self.search_result = self.ResultNoMatches self.cover_page_index = 0 @@ -97,7 +98,7 @@ class IssueIdentifier: def setOutputFunction( self, func ): self.output_function = func pass - + def calculateHash( self, image_data ): if self.image_hasher == '3': return ImageHasher( data=image_data ).dct_average_hash() @@ -130,6 +131,9 @@ class IssueIdentifier: def setProgressCallback( self, cb_func ): self.callback = cb_func + + def setCoverURLCallback( self, cb_func ): + self.coverUrlCallback = cb_func def getSearchKeys( self ): @@ -306,7 +310,6 @@ class IssueIdentifier: if self.callback is not None: self.callback( 0, len(series_shortlist)) - # now sort the list by name length series_shortlist.sort(key=lambda x: len(x['name']), reverse=False) @@ -358,6 +361,9 @@ class IssueIdentifier: self.match_list = [] return self.match_list + if self.coverUrlCallback is not None: + self.coverUrlCallback( url_image_data ) + url_image_hash = self.calculateHash( url_image_data ) score = ImageHasher.hamming_distance(cover_hash, url_image_hash) @@ -387,7 +393,6 @@ class IssueIdentifier: break self.log_msg( "" ) - if len(self.match_list) == 0: self.log_msg( ":-( no matches!" ) diff --git a/renamewindow.py b/renamewindow.py index b7b4f6b..5d5b4dc 100644 --- a/renamewindow.py +++ b/renamewindow.py @@ -23,6 +23,8 @@ from PyQt4 import QtCore, QtGui, uic from settings import ComicTaggerSettings from settingswindow import SettingsWindow from filerenamer import FileRenamer +from options import MetaDataStyle + import os import utils @@ -32,6 +34,7 @@ class RenameWindow(QtGui.QDialog): super(RenameWindow, self).__init__(parent) uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'renamewindow.ui' ), self) + self.label.setText("Preview (based on {0} tags):".format(MetaDataStyle.name[data_style])) self.settings = settings self.comic_archive_list = comic_archive_list diff --git a/settingswindow.ui b/settingswindow.ui index 827815d..b4d85b1 100644 --- a/settingswindow.ui +++ b/settingswindow.ui @@ -334,7 +334,7 @@ - Apply CBL Transforms on Batch/CLI Operations + Apply CBL Transforms on Batch Copy Operations to CBL Tags diff --git a/taggerwindow.py b/taggerwindow.py index 92529d6..2613127 100644 --- a/taggerwindow.py +++ b/taggerwindow.py @@ -51,6 +51,7 @@ from exportwindow import ExportWindow, ExportConflictOpts from pageloader import PageLoader from issueidentifier import IssueIdentifier from autotagstartwindow import AutoTagStartWindow +from autotagprogresswindow import AutoTagProgressWindow import utils import ctversion @@ -489,7 +490,6 @@ class TaggerWindow( QtGui.QMainWindow): self.lblCover.setPixmap(QtGui.QPixmap(img)) self.lblCover.setScaledContents(True) - def updateMenus( self ): # First just disable all the questionable items @@ -1468,7 +1468,7 @@ class TaggerWindow( QtGui.QMainWindow): print "Network error while getting issue details. Save aborted" if cv_md is not None: - if self.settings.apply_cbl_transform_on_bulk_operation: + if self.settings.apply_cbl_transform_on_cv_import: cv_md = CBLTransformer( cv_md, self.settings ).apply() QtGui.QApplication.restoreOverrideCursor() @@ -1476,7 +1476,7 @@ class TaggerWindow( QtGui.QMainWindow): return cv_md - def identifyAndTagSingleArchive( self, ca, match_results, abortOnLowConfidence ): + def identifyAndTagSingleArchive( self, ca, match_results, abortOnLowConfidence, dontUseYear ): success = False ii = IssueIdentifier( ca, self.settings ) @@ -1491,14 +1491,20 @@ class TaggerWindow( QtGui.QMainWindow): def myoutput( text ): IssueIdentifier.defaultWriteOutput( text ) + self.atprogdialog.textEdit.ensureCursorVisible() + self.atprogdialog.textEdit.insertPlainText(text) QtCore.QCoreApplication.processEvents() QtCore.QCoreApplication.processEvents() QtCore.QCoreApplication.processEvents() + if dontUseYear: + md.year = None ii.setAdditionalMetadata( md ) ii.onlyUseAdditionalMetaData = True ii.setOutputFunction( myoutput ) ii.cover_page_index = md.getCoverPageIndexList()[0] + ii.setCoverURLCallback( self.atprogdialog.setTestImage ) + matches = ii.search() result = ii.search_result @@ -1569,41 +1575,66 @@ class TaggerWindow( QtGui.QMainWindow): dlg.setModal( True ) if not dlg.exec_(): return - - progdialog = QtGui.QProgressDialog("", "Cancel", 0, len(ca_list), self) - progdialog.setWindowTitle( "Auto-Tagging" ) - progdialog.setWindowModality(QtCore.Qt.WindowModal) - progdialog.show() + + + self.atprogdialog = AutoTagProgressWindow( self) + self.atprogdialog.setModal(True) + #self.progdialog.rejected.connect( self.identifyCancel ) + self.atprogdialog.show() + self.atprogdialog.progressBar.setMaximum( len(ca_list) ) + self.atprogdialog.setWindowTitle( "Auto-Tagging" ) + prog_idx = 0 match_results = OnlineMatchResults() for ca in ca_list: + cover_idx = ca.readMetadata(style).getCoverPageIndexList()[0] + image_data = ca.getPage( cover_idx ) + self.atprogdialog.setArchiveImage( image_data ) + self.atprogdialog.setTestImage( None ) + QtCore.QCoreApplication.processEvents() - if progdialog.wasCanceled(): + if self.atprogdialog.isdone: break - progdialog.setValue(prog_idx) + self.atprogdialog.progressBar.setValue( prog_idx ) prog_idx += 1 - progdialog.setLabelText( ca.path ) - progdialog.setAutoClose( False ) + self.atprogdialog.label.setText( ca.path ) QtCore.QCoreApplication.processEvents() if ca.isWritable(): - success, match_results = self.identifyAndTagSingleArchive( ca, match_results, dlg.noAutoSaveOnLow ) + success, match_results = self.identifyAndTagSingleArchive( ca, match_results, dlg.noAutoSaveOnLow, dlg.dontUseYear ) - #if not success: - # QtGui.QMessageBox.warning(self, self.tr("Auto-Tag failed"), - # self.tr("The tagging operation seemed to fail for {0} Operation aborted!".format(ca.path))) - # break - - print "Good", match_results.goodMatches - print "multipleMatches", match_results.multipleMatches - print "noMatches", match_results.noMatches - print "fetchDataFailures", match_results.fetchDataFailures - print "writeFailures", match_results.writeFailures - - progdialog.close() + self.atprogdialog.close() self.fileSelectionList.updateSelectedRows() self.loadArchive( self.fileSelectionList.getCurrentArchive() ) + self.atprogdialog = None + + summary = "" + summary += "Successfully tagged archives: {0}\n".format( len(match_results.goodMatches)) + + if len ( match_results.multipleMatches ) > 0: + summary += "Archives with multiple matches: {0}\n".format( len(match_results.multipleMatches)) + if len ( match_results.noMatches ) > 0: + summary += "Archives with no matches: {0}\n".format( len(match_results.noMatches)) + if len ( match_results.fetchDataFailures ) > 0: + summary += "Archives that failed due to data fetch errors: {0}\n".format( len(match_results.fetchDataFailures)) + if len ( match_results.writeFailures ) > 0: + summary += "Archives that failed due to file writing errors: {0}\n".format( len(match_results.writeFailures)) + + if len ( match_results.multipleMatches ) > 0: + summary += "\n\nDo you want to manually select the ones with multiple matches now?" + + reply = QtGui.QMessageBox.question(self, + self.tr("Auto-Tag Summary"), + self.tr(summary), + QtGui.QMessageBox.Yes, QtGui.QMessageBox.No ) + + if reply == QtGui.QMessageBox.Yes: + print "TBD" + else: + QtGui.QMessageBox.information(self, self.tr("Auto-Tag Summary"), self.tr(summary)) + + diff --git a/todo.txt b/todo.txt index 42752f7..4b34cec 100644 --- a/todo.txt +++ b/todo.txt @@ -2,36 +2,34 @@ Features ----------------------------------------------------- +Re-arrange main form layout + +New menu graphics + auto tag + open folder vs file + Multi-file: File list: - Delete archive function?? + change menu order + Batch Functions: - - Batch Auto-Select - Start/Options Dialog - Progress Dialog - maybe reuse - -Show compared images to show progress in a sexy way + Auto-Tag Interactive dialog at end Summary Dialog Rename check-box for rows? - - Batch Tag Copy - Disallow overwrites? - + manual edit the preview? ----------------------------------------------------- Bugs ----------------------------------------------------- -Ultimate Spider-Man files can't be read - square bracket in folder name - (python:4401): GLib-ERROR **: Creating pipes for GWakeup: Too many open files + ----------------------------------------------------- Big Future Features -----------------------------------------------------