Added use of IssueIdentifier in the GUI
git-svn-id: http://comictagger.googlecode.com/svn/trunk@28 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
parent
d8a8355f5b
commit
a58442b8f6
@ -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
|
||||
|
||||
|
26
tagger.py
26
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:
|
||||
|
||||
|
@ -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_()
|
||||
|
||||
|
@ -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:
|
||||
|
@ -44,14 +44,14 @@
|
||||
<x>272</x>
|
||||
<y>430</y>
|
||||
<width>611</width>
|
||||
<height>29</height>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnIssues">
|
||||
<widget class="QPushButton" name="btnAutoSelect">
|
||||
<property name="text">
|
||||
<string>Show Issues</string>
|
||||
<string>Auto-Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -62,6 +62,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnIssues">
|
||||
<property name="text">
|
||||
<string>Show Issues</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
|
Loading…
Reference in New Issue
Block a user