diff --git a/issueidentifier.py b/issueidentifier.py index 8927220..6bc186e 100644 --- a/issueidentifier.py +++ b/issueidentifier.py @@ -39,6 +39,7 @@ class IssueIdentifier: self.min_score_distance = 2 self.additional_metadata = GenericMetadata() self.cv_api_key = cv_api_key + self.output_function = IssueIdentifier.defaultWriteOutput def setScoreMinThreshold( self, thresh ): self.min_score_thresh = thresh @@ -52,6 +53,10 @@ class IssueIdentifier: def setHasherAlgorithm( self, algo ): self.image_hasher = algo pass + + def setOutputFunction( self, func ): + self.output_function = func + pass def calculateHash( self, image_data ): if self.image_hasher == '3': @@ -118,57 +123,60 @@ class IssueIdentifier: search_keys['month'] = md_from_filename.publicationMonth return search_keys - + @staticmethod - def log_msg( msg , newline=True ): - sys.stdout.write(msg) - if newline: - sys.stdout.write("\n") + def defaultWriteOutput( text ): + sys.stdout.write(text) sys.stdout.flush() + def log_msg( self, msg , newline=True ): + self.output_function(msg) + if newline: + self.output_function("\n") + def search( self ): ca = self.comic_archive if not ca.seemsToBeAComicArchive(): - IssueIdentifier.log_msg( "Sorry, but "+ opts.filename + " is not a comic archive!") - return + self.log_msg( "Sorry, but "+ opts.filename + " is not a comic archive!") + return [] cover_image_data = ca.getCoverPage() cover_hash = self.calculateHash( cover_image_data ) - #IssueIdentifier.log_msg( "Cover hash = {0:016x}".format(cover_hash) ) + #self.log_msg( "Cover hash = {0:016x}".format(cover_hash) ) keys = self.getSearchKeys() # we need, at minimum, a series and issue number if keys['series'] is None or keys['issue_number'] is None: - IssueIdentifier.log_msg("Not enough info for a search!") - return None + self.log_msg("Not enough info for a search!") + return [] """ - IssueIdentifier.log_msg( "Going to search for:" ) - IssueIdentifier.log_msg( "Series: " + keys['series'] ) - IssueIdentifier.log_msg( "Issue : " + keys['issue_number'] ) + self.log_msg( "Going to search for:" ) + self.log_msg( "Series: " + keys['series'] ) + self.log_msg( "Issue : " + keys['issue_number'] ) if keys['year'] is not None: - IssueIdentifier.log_msg( "Year : " + keys['year'] ) + self.log_msg( "Year : " + keys['year'] ) if keys['month'] is not None: - IssueIdentifier.log_msg( "Month : " + keys['month'] ) + self.log_msg( "Month : " + keys['month'] ) """ comicVine = ComicVineTalker( self.cv_api_key ) - #IssueIdentifier.log_msg( ( "Searching for " + keys['series'] + "...") - IssueIdentifier.log_msg( "Searching for {0} #{1} ...".format( keys['series'], keys['issue_number']) ) + #self.log_msg( ( "Searching for " + keys['series'] + "...") + self.log_msg( "Searching for {0} #{1} ...".format( keys['series'], keys['issue_number']) ) keys['series'] = utils.removearticles( keys['series'] ) cv_search_results = comicVine.searchForSeries( keys['series'] ) - #IssueIdentifier.log_msg( "Found " + str(len(cv_search_results)) + " initial results" ) + #self.log_msg( "Found " + str(len(cv_search_results)) + " initial results" ) series_shortlist = [] - #IssueIdentifier.log_msg( "Removing results with too long names" ) + #self.log_msg( "Removing results with too long names" ) for item in cv_search_results: #assume that our search name is close to the actual name, say within 5 characters if len( utils.removearticles(item['name'])) < len( keys['series'] ) + 5: @@ -176,10 +184,10 @@ class IssueIdentifier: # if we don't think it's an issue number 1, remove any series' that are one-shots if keys['issue_number'] != '1': - #IssueIdentifier.log_msg( "Removing one-shots" ) + #self.log_msg( "Removing one-shots" ) series_shortlist[:] = [x for x in series_shortlist if not x['count_of_issues'] == 1] - IssueIdentifier.log_msg( "Searching in " + str(len(series_shortlist)) +" series" ) + self.log_msg( "Searching in " + str(len(series_shortlist)) +" series" ) # now sort the list by name length series_shortlist.sort(key=lambda x: len(x['name']), reverse=False) @@ -189,14 +197,14 @@ class IssueIdentifier: match_list = [] - IssueIdentifier.log_msg( "Fetching issue data", newline=False) + self.log_msg( "Fetching issue data", newline=False) for series in series_shortlist: - #IssueIdentifier.log_msg( "Fetching info for ID: {0} {1} ({2}) ...".format( + #self.log_msg( "Fetching info for ID: {0} {1} ({2}) ...".format( # series['id'], # series['name'], # series['start_year']) ) - IssueIdentifier.log_msg( ".", newline=False) + self.log_msg( ".", newline=False) cv_series_results = comicVine.fetchVolumeData( series['id'] ) issue_list = cv_series_results['issues'] @@ -224,14 +232,16 @@ class IssueIdentifier: match['url_image_hash'] = url_image_hash match['issue_title'] = issue['name'] match['img_url'] = thumb_url + match['issue_id'] = issue['id'] + match['volume_id'] = series['id'] match_list.append(match) break - IssueIdentifier.log_msg( "done!" ) + self.log_msg( "done!" ) if len(match_list) == 0: - IssueIdentifier.log_msg( ":-( no matches!" ) - return + self.log_msg( ":-( no matches!" ) + return match_list # sort list by image match scores match_list.sort(key=lambda k: k['distance']) @@ -240,11 +250,11 @@ class IssueIdentifier: for i in match_list: l.append( i['distance'] ) - IssueIdentifier.log_msg( "Compared {0} covers".format(len(match_list)), newline=False) - IssueIdentifier.log_msg( str(l)) + self.log_msg( "Compared {0} covers".format(len(match_list)), newline=False) + self.log_msg( str(l)) def print_match(item): - IssueIdentifier.log_msg( u"-----> {0} #{1} {2} -- score: {3}\n-------> url:{4}".format( + self.log_msg( u"-----> {0} #{1} {2} -- score: {3}\n-------> url:{4}".format( item['series'], item['issue_number'], item['issue_title'], @@ -255,13 +265,13 @@ class IssueIdentifier: if len(match_list) == 1: if best_score > self.min_score_thresh: - IssueIdentifier.log_msg( "!!!! Very weak score for the cover. Maybe it's not the cover?" ) + self.log_msg( "!!!! Very weak score for the cover. Maybe it's not the cover?" ) print_match(match_list[0]) - return + return match_list elif best_score > self.min_score_thresh and len(match_list) > 1: - IssueIdentifier.log_msg( "No good image matches! Need to use other info..." ) - return + self.log_msg( "No good image matches! Need to use other info..." ) + return match_list #now pare down list, remove any item more than specified distant from the top scores for item in reversed(match_list): @@ -270,15 +280,14 @@ class IssueIdentifier: if len(match_list) == 1: print_match(match_list[0]) - return elif len(match_list) == 0: - IssueIdentifier.log_msg( "No matches found :(" ) - return - + self.log_msg( "No matches found :(" ) else: print - IssueIdentifier.log_msg( "More than one likley candiate. Maybe a lexical comparison??" ) + self.log_msg( "More than one likley candiate. Maybe a lexical comparison??" ) for item in match_list: print_match(item) - + + return match_list + \ No newline at end of file diff --git a/tagger.py b/tagger.py index 9bc2602..c80acde 100755 --- a/tagger.py +++ b/tagger.py @@ -35,7 +35,7 @@ from issueidentifier import IssueIdentifier import utils #----------------------------- -def cliProcedure( opts, settings ): +def cli_mode( opts, settings ): ca = ComicArchive(opts.filename) if not ca.seemsToBeAComicArchive(): @@ -43,17 +43,23 @@ def cliProcedure( opts, settings ): return ii = IssueIdentifier( ca, settings.cv_api_key ) - ii.search() + matches = ii.search() """ - # now get the particular issue data - metadata = comicVine.fetchIssueData( series_id, opts.issue_number ) - - #pprint( cv_volume_data, indent=4 ) - - ca = ComicArchive(opts.filename) - ca.writeMetadata( metadata, opts.data_style ) + if len(matches) == 1: + + # now get the particular issue data + metadata = comicVine.fetchIssueData( match[0]['series'], match[0]['issue_number'] ) + + # write out the new data + ca.writeMetadata( metadata, opts.data_style ) + + elif len(matches) == 0: + pass + elif len(matches) == 0: + # print match options, with CV issue ID's + pass """ #----------------------------- @@ -69,7 +75,7 @@ def main(): if opts.no_gui: - cliProcedure( opts, settings ) + cli_mode( opts, settings ) else: diff --git a/taggerwindow.py b/taggerwindow.py index f5c76fa..31c04dc 100644 --- a/taggerwindow.py +++ b/taggerwindow.py @@ -555,7 +555,7 @@ class TaggerWindow( QtGui.QMainWindow): issue_number = str(self.leIssueNum.text()).strip() - selector = VolumeSelectionWindow( self, self.settings.cv_api_key, series_name, issue_number ) + selector = VolumeSelectionWindow( self, self.settings.cv_api_key, series_name, issue_number, self.comic_archive ) selector.setModal(True) selector.exec_() diff --git a/volumeselectionwindow.py b/volumeselectionwindow.py index 2f03312..72f4f11 100644 --- a/volumeselectionwindow.py +++ b/volumeselectionwindow.py @@ -26,12 +26,14 @@ from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest from comicvinetalker import ComicVineTalker from issueselectionwindow import IssueSelectionWindow +from issueidentifier import IssueIdentifier +from genericmetadata import GenericMetadata class VolumeSelectionWindow(QtGui.QDialog): volume_id = 0 - def __init__(self, parent, cv_api_key, series_name, issue_number): + def __init__(self, parent, cv_api_key, series_name, issue_number, comic_archive): super(VolumeSelectionWindow, self).__init__(parent) uic.loadUi('volumeselectionwindow.ui', self) @@ -39,6 +41,7 @@ class VolumeSelectionWindow(QtGui.QDialog): self.series_name = series_name self.issue_number = issue_number self.cv_api_key = cv_api_key + self.comic_archive = comic_archive self.performQuery() @@ -47,6 +50,7 @@ class VolumeSelectionWindow(QtGui.QDialog): 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.twList.selectRow(0) @@ -54,6 +58,22 @@ class VolumeSelectionWindow(QtGui.QDialog): self.performQuery() self.twList.selectRow(0) + def autoSelect( self ): + ii = IssueIdentifier( self.comic_archive, self.cv_api_key ) + + md = GenericMetadata() + md.series = self.series_name + md.issue_number = self.issue_number + ii.setAdditionalMetadata( md ) + + matches = ii.search() + if len(matches) == 1: + print "VolumeSelectionWindow found a match!!", matches[0]['volume_id'], matches[0]['issue_number'] + self.volume_id = matches[0]['volume_id'] + self.issue_number = matches[0]['issue_number'] + self.selectByID() + self.showIssues() + def showIssues( self ): selector = IssueSelectionWindow( self, self.cv_api_key, self.volume_id, self.issue_number ) selector.setModal(True) @@ -64,6 +84,13 @@ class VolumeSelectionWindow(QtGui.QDialog): 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 ): while self.twList.rowCount() > 0: diff --git a/volumeselectionwindow.ui b/volumeselectionwindow.ui index e744b1a..be0e902 100644 --- a/volumeselectionwindow.ui +++ b/volumeselectionwindow.ui @@ -44,14 +44,14 @@ 272 430 611 - 29 + 32 - + - Show Issues + Auto-Select @@ -62,6 +62,13 @@ + + + + Show Issues + + +