diff --git a/comictaggerlib/autotagstartwindow.py b/comictaggerlib/autotagstartwindow.py
index d23658a..72a9257 100644
--- a/comictaggerlib/autotagstartwindow.py
+++ b/comictaggerlib/autotagstartwindow.py
@@ -58,7 +58,9 @@ class AutoTagStartWindow(QtGui.QDialog):
if self.settings.ignore_leading_numbers_in_filename:
self.cbxIgnoreLeadingDigitsInFilename.setCheckState( QtCore.Qt.Checked)
if self.settings.remove_archive_after_successful_match:
- self.cbxRemoveAfterSuccess.setCheckState( QtCore.Qt.Checked)
+ self.cbxRemoveAfterSuccess.setCheckState( QtCore.Qt.Checked)
+ if self.settings.wait_and_retry_on_rate_limit:
+ self.cbxWaitForRateLimit.setCheckState( QtCore.Qt.Checked)
nlmtTip = (
""" The Name Length Match Tolerance is for eliminating automatic
@@ -90,6 +92,7 @@ class AutoTagStartWindow(QtGui.QDialog):
self.assumeIssueOne = False
self.ignoreLeadingDigitsInFilename = False
self.removeAfterSuccess = False
+ self.waitAndRetryOnRateLimit = False
self.searchString = None
self.nameLengthMatchTolerance = self.settings.id_length_delta_thresh
@@ -107,6 +110,7 @@ class AutoTagStartWindow(QtGui.QDialog):
self.ignoreLeadingDigitsInFilename = self.cbxIgnoreLeadingDigitsInFilename.isChecked()
self.removeAfterSuccess = self.cbxRemoveAfterSuccess.isChecked()
self.nameLengthMatchTolerance = int(self.leNameLengthMatchTolerance.text())
+ self.waitAndRetryOnRateLimit = self.cbxWaitForRateLimit.isChecked()
#persist some settings
self.settings.save_on_low_confidence = self.autoSaveOnLow
@@ -114,6 +118,7 @@ class AutoTagStartWindow(QtGui.QDialog):
self.settings.assume_1_if_no_issue_num = self.assumeIssueOne
self.settings.ignore_leading_numbers_in_filename = self.ignoreLeadingDigitsInFilename
self.settings.remove_archive_after_successful_match = self.removeAfterSuccess
+ self.settings.wait_and_retry_on_rate_limit = self.waitAndRetryOnRateLimit
if self.cbxSpecifySearchString.isChecked():
self.searchString = unicode(self.leSearchString.text())
diff --git a/comictaggerlib/cli.py b/comictaggerlib/cli.py
index ee10725..34b9a5d 100644
--- a/comictaggerlib/cli.py
+++ b/comictaggerlib/cli.py
@@ -60,11 +60,13 @@ class OnlineMatchResults():
#-----------------------------
-def actual_issue_data_fetch( match, settings ):
+def actual_issue_data_fetch( match, settings, opts ):
# now get the particular issue data
try:
- cv_md = ComicVineTalker().fetchIssueData( match['volume_id'], match['issue_number'], settings )
+ comicVine = ComicVineTalker()
+ comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit
+ cv_md = comicVine.fetchIssueData( match['volume_id'], match['issue_number'], settings )
except ComicVineTalkerException:
print >> sys.stderr, "Network error while getting issue details. Save aborted"
return None
@@ -117,7 +119,7 @@ def display_match_set_for_choice( label, match_set, opts, settings ):
# we know at this point, that the file is all good to go
ca = ComicArchive( match_set.filename, settings.rar_exe_path )
md = create_local_metadata( opts, ca, ca.hasMetadata(opts.data_style) )
- cv_md = actual_issue_data_fetch(match_set.matches[int(i)], settings)
+ cv_md = actual_issue_data_fetch(match_set.matches[int(i)], settings, opts)
md.overlay( cv_md )
actual_metadata_save( ca, opts, md )
@@ -346,7 +348,9 @@ def process_file_cli( filename, opts, settings, match_results ):
if opts.issue_id is not None:
# we were given the actual ID to search with
try:
- cv_md = ComicVineTalker().fetchIssueDataByIssueID( opts.issue_id, settings )
+ 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 >> sys.stderr,"Network error while getting issue details. Save aborted"
match_results.fetchDataFailures.append(filename)
@@ -374,6 +378,7 @@ def process_file_cli( filename, opts, settings, match_results ):
# 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()
@@ -421,7 +426,7 @@ def process_file_cli( filename, opts, settings, match_results ):
# we got here, so we have a single match
# now get the particular issue data
- cv_md = actual_issue_data_fetch(matches[0], settings)
+ cv_md = actual_issue_data_fetch(matches[0], settings, opts)
if cv_md is None:
match_results.fetchDataFailures.append(filename)
return
diff --git a/comictaggerlib/comicarchive.py b/comictaggerlib/comicarchive.py
index 4988af4..d5667ef 100644
--- a/comictaggerlib/comicarchive.py
+++ b/comictaggerlib/comicarchive.py
@@ -764,7 +764,7 @@ class ComicArchive:
# make a sub-list of image files
self.page_list = []
for name in files:
- if ( name[-4:].lower() in [ ".jpg", "jpeg", ".png", ".gif" ] and os.path.basename(name)[0] != "." ):
+ if ( name[-4:].lower() in [ ".jpg", "jpeg", ".png", ".gif", "webp" ] and os.path.basename(name)[0] != "." ):
self.page_list.append(name)
return self.page_list
diff --git a/comictaggerlib/comicvinetalker.py b/comictaggerlib/comicvinetalker.py
index cc15794..0b68ba9 100644
--- a/comictaggerlib/comicvinetalker.py
+++ b/comictaggerlib/comicvinetalker.py
@@ -55,19 +55,50 @@ class CVTypeID:
Issue = "4000"
class ComicVineTalkerException(Exception):
- pass
+ Unknown = -1
+ Network = -2
+ InvalidKey = 100
+ RateLimit = 107
+
+ def __init__(self, code=-1, desc=""):
+ self.desc = desc
+ self.code = code
+
+ def __str__(self):
+ if (self.code == ComicVineTalkerException.Unknown or
+ self.code == ComicVineTalkerException.Network):
+ return self.desc
+ else:
+ return "CV error #{0}: [{1}]. \n".format( self.code, self.desc )
+
+
class ComicVineTalker(QObject):
logo_url = "http://static.comicvine.com/bundles/comicvinesite/images/logo.png"
+ api_key = ""
- def __init__(self, api_key=""):
+ @staticmethod
+ def getRateLimitMessage():
+ if ComicVineTalker.api_key == "":
+ return "Comic Vine rate limit exceeded. You should configue your own Comic Vine API key."
+ else:
+ return "Comic Vine rate limit exceeded. Please wait a bit."
+
+
+ def __init__(self):
QObject.__init__(self)
self.api_base_url = "http://www.comicvine.com/api"
+ self.wait_for_rate_limit = False
# key that is registered to comictagger
- self.api_key = '27431e6787042105bd3e47e169a624521f89f3a4'
+ default_api_key = '27431e6787042105bd3e47e169a624521f89f3a4'
+
+ if ComicVineTalker.api_key == "":
+ self.api_key = default_api_key
+ else:
+ self.api_key = ComicVineTalker.api_key
self.log_func = None
@@ -95,9 +126,9 @@ class ComicVineTalker(QObject):
day = parts[2]
return day, month, year
- def testKey( self ):
+ def testKey( self, key ):
- test_url = self.api_base_url + "/issue/1/?api_key=" + self.api_key + "&format=json&field_list=name"
+ test_url = self.api_base_url + "/issue/1/?api_key=" + key + "&format=json&field_list=name"
resp = urllib2.urlopen( test_url )
content = resp.read()
@@ -106,6 +137,36 @@ class ComicVineTalker(QObject):
# Bogus request, but if the key is wrong, you get error 100: "Invalid API Key"
return cv_response[ 'status_code' ] != 100
+ """
+ Get the contect from the CV server. If we're in "wait mode" and status code is a rate limit error
+ sleep for a bit and retry.
+ """
+ def getCVContent(self, url):
+ total_time_waited = 0
+ limit_wait_time = 1
+ counter = 0
+ wait_times = [1,2,3,4]
+ while True:
+ content = self.getUrlContent(url)
+ cv_response = json.loads(content)
+ if self.wait_for_rate_limit and cv_response[ 'status_code' ] == ComicVineTalkerException.RateLimit:
+ self.writeLog( "Rate limit encountered. Waiting for {0} minutes\n".format(limit_wait_time))
+ time.sleep(limit_wait_time * 60)
+ total_time_waited += limit_wait_time
+ limit_wait_time = wait_times[counter]
+ if counter < 3:
+ counter += 1
+ # don't wait much more than 20 minutes
+ if total_time_waited < 20:
+ continue
+ if cv_response[ 'status_code' ] != 1:
+ self.writeLog( "Comic Vine query failed with error #{0}: [{1}]. \n".format( cv_response[ 'status_code' ], cv_response[ 'error' ] ))
+ raise ComicVineTalkerException(cv_response[ 'status_code' ], cv_response[ 'error' ] )
+ else:
+ # it's all good
+ break
+ return cv_response
+
def getUrlContent( self, url ):
# connect to server:
# if there is a 500 error, try a few more times before giving up
@@ -126,9 +187,9 @@ class ComicVineTalker(QObject):
except Exception as e:
self.writeLog( str(e) + "\n" )
- raise ComicVineTalkerException("Network Error!")
+ raise ComicVineTalkerException(ComicVineTalkerException.Network, "Network Error!")
- raise ComicVineTalkerException("Error on Comic Vine server")
+ raise ComicVineTalkerException(ComicVineTalkerException.Unknown, "Error on Comic Vine server")
def searchForSeries( self, series_name , callback=None, refresh_cache=False ):
@@ -161,14 +222,8 @@ class ComicVineTalker(QObject):
query_string = urllib.quote_plus(query_string.encode("utf-8"))
search_url = self.api_base_url + "/search/?api_key=" + self.api_key + "&format=json&resources=volume&query=" + query_string + "&field_list=name,id,start_year,publisher,image,description,count_of_issues"
- content = self.getUrlContent(search_url + "&page=1")
-
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- self.writeLog( "Comic Vine query failed with error: [{0}]. \n".format( cv_response[ 'error' ] ))
- return None
-
+ cv_response = self.getCVContent(search_url + "&page=1")
+
search_results = list()
# see http://api.comicvine.com/documentation/#handling_responses
@@ -190,14 +245,9 @@ class ComicVineTalker(QObject):
if callback is None:
self.writeLog("getting another page of results {0} of {1}...\n".format( current_result_count, total_result_count))
page += 1
+
+ cv_response = self.getCVContent(search_url + "&page="+str(page))
- content = self.getUrlContent(search_url + "&page="+str(page))
-
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- self.writeLog( "Comic Vine query failed with error: [{0}]. \n".format( cv_response[ 'error' ] ))
- return None
search_results.extend( cv_response['results'])
current_result_count += cv_response['number_of_page_results']
@@ -229,12 +279,7 @@ class ComicVineTalker(QObject):
volume_url = self.api_base_url + "/volume/" + CVTypeID.Volume + "-" + str(series_id) + "/?api_key=" + self.api_key + "&field_list=name,id,start_year,publisher,count_of_issues&format=json"
- content = self.getUrlContent(volume_url)
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- print >> sys.stderr, "Comic Vine query failed with error: [{0}]. ".format( cv_response[ 'error' ] )
- return None
+ cv_response = self.getCVContent(volume_url)
volume_results = cv_response['results']
@@ -254,12 +299,8 @@ class ComicVineTalker(QObject):
#---------------------------------
issues_url = self.api_base_url + "/issues/" + "?api_key=" + self.api_key + "&filter=volume:" + str(series_id) + "&field_list=id,volume,issue_number,name,image,cover_date,site_detail_url,description&format=json"
- content = self.getUrlContent(issues_url)
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- print >> sys.stderr, "Comic Vine query failed with error: [{0}]. ".format( cv_response[ 'error' ] )
- return None
+ cv_response = self.getCVContent(issues_url)
+
#------------------------------------
limit = cv_response['limit']
@@ -279,12 +320,8 @@ class ComicVineTalker(QObject):
offset += cv_response['number_of_page_results']
#print issues_url+ "&offset="+str(offset)
- content = self.getUrlContent(issues_url + "&offset="+str(offset))
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- self.writeLog( "Comic Vine query failed with error: [{0}]. \n".format( cv_response[ 'error' ] ))
- return None
+ cv_response = self.getCVContent(issues_url + "&offset="+str(offset))
+
volume_issues_result.extend( cv_response['results'])
current_result_count += cv_response['number_of_page_results']
@@ -310,12 +347,8 @@ class ComicVineTalker(QObject):
issues_url = self.api_base_url + "/issues/" + "?api_key=" + self.api_key + filter + "&field_list=id,volume,issue_number,name,image,cover_date,site_detail_url,description&format=json"
- content = self.getUrlContent(issues_url)
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- print >> sys.stderr, "Comic Vine query failed with error: [{0}]. ".format( cv_response[ 'error' ] )
- return None
+ cv_response = self.getCVContent(issues_url)
+
#------------------------------------
limit = cv_response['limit']
@@ -335,12 +368,8 @@ class ComicVineTalker(QObject):
offset += cv_response['number_of_page_results']
#print issues_url+ "&offset="+str(offset)
- content = self.getUrlContent(issues_url + "&offset="+str(offset))
- cv_response = json.loads(content)
-
- if cv_response[ 'status_code' ] != 1:
- self.writeLog( "Comic Vine query failed with error: [{0}]. \n".format( cv_response[ 'error' ] ))
- return None
+ cv_response = self.getCVContent(issues_url + "&offset="+str(offset))
+
filtered_issues_result.extend( cv_response['results'])
current_result_count += cv_response['number_of_page_results']
@@ -366,11 +395,7 @@ class ComicVineTalker(QObject):
if (found):
issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + str(record['id']) + "/?api_key=" + self.api_key + "&format=json"
- content = self.getUrlContent(issue_url)
- cv_response = json.loads(content)
- if cv_response[ 'status_code' ] != 1:
- print >> sys.stderr, "Comic Vine query failed with error: [{0}]. ".format( cv_response[ 'error' ] )
- return None
+ cv_response = self.getCVContent(issue_url)
issue_results = cv_response['results']
else:
@@ -382,11 +407,7 @@ class ComicVineTalker(QObject):
def fetchIssueDataByIssueID( self, issue_id, settings ):
issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + str(issue_id) + "/?api_key=" + self.api_key + "&format=json"
- content = self.getUrlContent(issue_url)
- cv_response = json.loads(content)
- if cv_response[ 'status_code' ] != 1:
- print >> sys.stderr, "Comic Vine query failed with error: [{0}]. ".format( cv_response[ 'error' ] )
- return None
+ cv_response = self.getCVContent(issue_url)
issue_results = cv_response['results']
@@ -577,19 +598,14 @@ class ComicVineTalker(QObject):
issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + str(issue_id) + "/?api_key=" + self.api_key + "&format=json&field_list=image,cover_date,site_detail_url"
- content = self.getUrlContent(issue_url)
-
details = dict()
details['image_url'] = None
details['thumb_image_url'] = None
details['cover_date'] = None
details['site_detail_url'] = None
- cv_response = json.loads(content)
- if cv_response[ 'status_code' ] != 1:
- print >> sys.stderr, "Comic Vine query failed with error: [{0}]. ".format( cv_response[ 'error' ] )
- return details
-
+ cv_response = self.getCVContent(issue_url)
+
details['image_url'] = cv_response['results']['image']['super_url']
details['thumb_image_url'] = cv_response['results']['image']['thumb_url']
details['cover_date'] = cv_response['results']['cover_date']
diff --git a/comictaggerlib/coverimagewidget.py b/comictaggerlib/coverimagewidget.py
index 55154cf..c109696 100644
--- a/comictaggerlib/coverimagewidget.py
+++ b/comictaggerlib/coverimagewidget.py
@@ -237,8 +237,7 @@ class CoverImageWidget(QWidget):
# called when the image is done loading from internet
def coverRemoteFetchComplete( self, image_data, issue_id ):
- img = QImage()
- img.loadFromData( image_data )
+ img = utils.getQImageFromData( image_data)
self.current_pixmap = QPixmap(img)
self.setDisplayPixmap( 0, 0)
#print "ATB cover fetch complete!"
diff --git a/comictaggerlib/ctversion.py b/comictaggerlib/ctversion.py
index a0b2511..8d86cf7 100644
--- a/comictaggerlib/ctversion.py
+++ b/comictaggerlib/ctversion.py
@@ -1,3 +1,3 @@
# This file should contan only these comments, and the line below.
# Used by packaging makefiles and app
-version="1.1.14-beta"
+version="1.1.15-beta"
diff --git a/comictaggerlib/imagehasher.py b/comictaggerlib/imagehasher.py
index fb26397..3441d8e 100755
--- a/comictaggerlib/imagehasher.py
+++ b/comictaggerlib/imagehasher.py
@@ -21,7 +21,8 @@ import StringIO
import sys
try:
- import Image
+ from PIL import Image
+ from PIL import WebPImagePlugin
pil_available = True
except ImportError:
pil_available = False
diff --git a/comictaggerlib/issueidentifier.py b/comictaggerlib/issueidentifier.py
index 3ac17c2..6cf351d 100644
--- a/comictaggerlib/issueidentifier.py
+++ b/comictaggerlib/issueidentifier.py
@@ -23,7 +23,8 @@ import math
import urllib2, urllib
import StringIO
try:
- import Image
+ from PIL import Image
+ from PIL import WebPImagePlugin
pil_available = True
except ImportError:
pil_available = False
@@ -83,6 +84,7 @@ class IssueIdentifier:
self.search_result = self.ResultNoMatches
self.cover_page_index = 0
self.cancel = False
+ self.waitAndRetryOnRateLimit = False
def setScoreMinThreshold( self, thresh ):
self.min_score_thresh = thresh
@@ -377,8 +379,9 @@ class IssueIdentifier:
self.log_msg( "\tMonth : " + str(keys['month']) )
#self.log_msg("Publisher Blacklist: " + str(self.publisher_blacklist))
-
comicVine = ComicVineTalker( )
+ comicVine.wait_for_rate_limit = self.waitAndRetryOnRateLimit
+
comicVine.setLogFunc( self.output_function )
#self.log_msg( ( "Searching for " + keys['series'] + "...")
@@ -393,6 +396,9 @@ class IssueIdentifier:
if self.cancel == True:
return []
+ if cv_search_results == None:
+ return []
+
series_second_round_list = []
#self.log_msg( "Removing results with too long names, banned publishers, or future start dates" )
@@ -443,6 +449,9 @@ class IssueIdentifier:
self.log_msg( "Network issue while searching for series details. Aborting...")
return []
+ if issue_list is None:
+ return []
+
shortlist = list()
#now re-associate the issues and volumes
for issue in issue_list:
diff --git a/comictaggerlib/issueselectionwindow.py b/comictaggerlib/issueselectionwindow.py
index 6549392..2272f61 100644
--- a/comictaggerlib/issueselectionwindow.py
+++ b/comictaggerlib/issueselectionwindow.py
@@ -92,12 +92,15 @@ class IssueSelectionWindow(QtGui.QDialog):
QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
try:
- comicVine = ComicVineTalker( )
+ comicVine = ComicVineTalker()
volume_data = comicVine.fetchVolumeData( self.series_id )
self.issue_list = comicVine.fetchIssuesByVolume( self.series_id )
- except ComicVineTalkerException:
- QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.critical(self, self.tr("Network Issue"), self.tr("Could not connect to ComicVine to list issues!"))
+ except ComicVineTalkerException as e:
+ QtGui.QApplication.restoreOverrideCursor()
+ if e.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 ComicVine to list issues!"))
return
while self.twList.rowCount() > 0:
diff --git a/comictaggerlib/main.py b/comictaggerlib/main.py
index 883603b..f3c9cdf 100755
--- a/comictaggerlib/main.py
+++ b/comictaggerlib/main.py
@@ -28,6 +28,7 @@ import utils
import cli
from settings import ComicTaggerSettings
from options import Options
+from comicvinetalker import ComicVineTalker
try:
qt_available = True
@@ -40,9 +41,20 @@ except ImportError as e:
def ctmain():
utils.fix_output_encoding()
settings = ComicTaggerSettings()
-
+
opts = Options()
opts.parseCmdLineArgs()
+
+ # manage the CV API key
+ if opts.cv_api_key:
+ if opts.cv_api_key != settings.cv_api_key:
+ settings.cv_api_key = opts.cv_api_key
+ settings.save()
+ if opts.only_set_key:
+ print "Key set"
+ return
+
+ ComicVineTalker.api_key = settings.cv_api_key
signal.signal(signal.SIGINT, signal.SIG_DFL)
diff --git a/comictaggerlib/options.py b/comictaggerlib/options.py
index 7a252a3..63e6e6b 100644
--- a/comictaggerlib/options.py
+++ b/comictaggerlib/options.py
@@ -42,50 +42,53 @@ A utility for reading and writing metadata to comic archives.
If no options are given, {0} will run in windowed mode
- -p, --print Print out tag info from file. Specify type
- (via -t) to get only info of that tag type
- --raw With -p, will print out the raw tag block(s)
- from the file
- -d, --delete Deletes the tag block of specified type (via -t)
- -c, --copy=SOURCE Copy the specified source tag block to destination style
- specified via via -t (potentially lossy operation)
- -s, --save Save out tags as specified type (via -t)
- Must specify also at least -o, -p, or -m
- --nooverwrite Don't modify tag block if it already exists ( relevent for -s or -c )
- -1, --assume-issue-one Assume issue number is 1 if not found ( relevent for -s )
- -n, --dryrun Don't actually modify file (only relevent for -d, -s, or -r)
- -t, --type=TYPE Specify TYPE as either "CR", "CBL", or "COMET" (as either
- ComicRack, ComicBookLover, or CoMet style tags, respectivly)
- -f, --parsefilename Parse the filename to get some info, specifically
- series name, issue number, volume, and publication
- year
- -i, --interactive Interactively query the user when there are multiple matches for
- an online search
- --nosummary Suppress the default summary after a save operation
- -o, --online Search online and attempt to identify file using
- existing metadata and images in archive. May be used
- in conjuntion with -f and -m
- --id=ID Use the issue ID when searching online. Overrides all other metadata
- -m, --metadata=LIST Explicity define, as a list, some tags to be used
- e.g. "series=Plastic Man , publisher=Quality Comics"
- "series=Kickers^, Inc., issue=1, year=1986"
- Name-Value pairs are comma separated. Use a "^" to
- escape an "=" or a ",", as shown in the example above
- Some names that can be used:
- series, issue, issueCount, year, publisher, title
- -r, --rename Rename the file based on specified tag style.
- --noabort Don't abort save operation when online match is of low confidence
- -e, --export-to-zip Export RAR archive to Zip format
- --delete-rar Delete original RAR archive after successful export to Zip
- --abort-on-conflict Don't export to zip if intended new filename exists (Otherwise, creates
- a new unique filename)
- -S, --script=FILE Run an "add-on" python script that uses the comictagger library for custom
- processing. Script arguments can follow the script name
- -R, --recursive Recursively include files in sub-folders
- -v, --verbose Be noisy when doing what it does
- --terse Don't say much (for print mode)
- --version Display version
- -h, --help Display this message
+ -p, --print Print out tag info from file. Specify type
+ (via -t) to get only info of that tag type
+ --raw With -p, will print out the raw tag block(s)
+ from the file
+ -d, --delete Deletes the tag block of specified type (via -t)
+ -c, --copy=SOURCE Copy the specified source tag block to destination style
+ specified via via -t (potentially lossy operation)
+ -s, --save Save out tags as specified type (via -t)
+ Must specify also at least -o, -p, or -m
+ --nooverwrite Don't modify tag block if it already exists ( relevent for -s or -c )
+ -1, --assume-issue-one Assume issue number is 1 if not found ( relevent for -s )
+ -n, --dryrun Don't actually modify file (only relevent for -d, -s, or -r)
+ -t, --type=TYPE Specify TYPE as either "CR", "CBL", or "COMET" (as either
+ ComicRack, ComicBookLover, or CoMet style tags, respectivly)
+ -f, --parsefilename Parse the filename to get some info, specifically
+ series name, issue number, volume, and publication
+ year
+ -i, --interactive Interactively query the user when there are multiple matches for
+ an online search
+ --nosummary Suppress the default summary after a save operation
+ -o, --online Search online and attempt to identify file using
+ existing metadata and images in archive. May be used
+ in conjuntion with -f and -m
+ --id=ID Use the issue ID when searching online. Overrides all other metadata
+ -m, --metadata=LIST Explicity define, as a list, some tags to be used
+ e.g. "series=Plastic Man , publisher=Quality Comics"
+ "series=Kickers^, Inc., issue=1, year=1986"
+ Name-Value pairs are comma separated. Use a "^" to
+ escape an "=" or a ",", as shown in the example above
+ Some names that can be used:
+ series, issue, issueCount, year, publisher, title
+ -r, --rename Rename the file based on specified tag style.
+ --noabort Don't abort save operation when online match is of low confidence
+ -e, --export-to-zip Export RAR archive to Zip format
+ --delete-rar Delete original RAR archive after successful export to Zip
+ --abort-on-conflict Don't export to zip if intended new filename exists (Otherwise, creates
+ a new unique filename)
+ -S, --script=FILE Run an "add-on" python script that uses the comictagger library for custom
+ processing. Script arguments can follow the script name
+ -R, --recursive Recursively include files in sub-folders
+ --cv-api-key=KEY Use the given Comic Vine API Key (persisted in settings)
+ --only-set-cv-key Only set the Comiv Vine API key and quit
+ -w, --wait-on-cv-rate-limit When encountering a Comic Vine rate limit error, wait and retry query
+ -v, --verbose Be noisy when doing what it does
+ --terse Don't say much (for print mode)
+ --version Display version
+ -h, --help Display this message
For more help visit the wiki at: http://code.google.com/p/comictagger/
"""
@@ -111,6 +114,8 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
self.parse_filename = False
self.show_save_summary = True
self.raw = False
+ self.cv_api_key = None
+ self.only_set_key = False
self.rename_file = False
self.no_overwrite = False
self.interactive = False
@@ -118,8 +123,10 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
self.recursive = False
self.run_script = False
self.script = None
+ self.wait_and_retry_on_rate_limit = False
self.assume_issue_is_one_if_not_set = False
self.file_list = []
+
def display_msg_and_quit( self, msg, code, show_help=False ):
appname = os.path.basename(sys.argv[0])
@@ -235,11 +242,12 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
# parse command line options
try:
opts, args = getopt.getopt( input_args,
- "hpdt:fm:vonsrc:ieRS:1",
+ "hpdt:fm:vownsrc:ieRS:1",
[ "help", "print", "delete", "type=", "copy=", "parsefilename", "metadata=", "verbose",
"online", "dryrun", "save", "rename" , "raw", "noabort", "terse", "nooverwrite",
"interactive", "nosummary", "version", "id=" , "recursive", "script=",
- "export-to-zip", "delete-rar", "abort-on-conflict", "assume-issue-one" ] )
+ "export-to-zip", "delete-rar", "abort-on-conflict", "assume-issue-one",
+ "cv-api-key=", "only-set-cv-key", "wait-on-cv-rate-limit" ] )
except getopt.GetoptError as err:
self.display_msg_and_quit( str(err), 2 )
@@ -289,6 +297,8 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
self.abort_export_on_conflict = True
if o in ("-f", "--parsefilename"):
self.parse_filename = True
+ if o in ("-w", "--wait-on-cv-rate-limit"):
+ self.wait_and_retry_on_rate_limit = True
if o == "--id":
self.issue_id = a
if o == "--raw":
@@ -303,6 +313,10 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
self.assume_issue_is_one_if_not_set = True
if o == "--nooverwrite":
self.no_overwrite = True
+ if o == "--cv-api-key":
+ self.cv_api_key = a
+ if o == "--only-set-cv-key":
+ self.only_set_key = True
if o == "--version":
print "ComicTagger {0}: Copyright (c) 2012-2014 Anthony Beville".format(ctversion.version)
print "Distributed under Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)"
@@ -322,7 +336,7 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
else:
self.display_msg_and_quit( "Invalid tag type", 1 )
- if self.print_tags or self.delete_tags or self.save_tags or self.copy_tags or self.rename_file or self.export_to_zip:
+ if self.print_tags or self.delete_tags or self.save_tags or self.copy_tags or self.rename_file or self.export_to_zip or self.only_set_key:
self.no_gui = True
count = 0
@@ -333,9 +347,10 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
if self.copy_tags: count += 1
if self.rename_file: count += 1
if self.export_to_zip: count +=1
+ if self.only_set_key: count +=1
if count > 1:
- self.display_msg_and_quit( "Must choose only one action of print, delete, save, copy, rename, export, or run script", 1 )
+ self.display_msg_and_quit( "Must choose only one action of print, delete, save, copy, rename, export, set key, or run script", 1 )
if self.script is not None:
self.launch_script( self.script )
@@ -352,8 +367,11 @@ For more help visit the wiki at: http://code.google.com/p/comictagger/
else:
self.filename = args[0]
self.file_list = args
+
+ if self.only_set_key and self.cv_api_key == None:
+ self.display_msg_and_quit( "Key not given!", 1 )
- if self.no_gui and self.filename is None:
+ if (self.only_set_key == False) and self.no_gui and (self.filename is None):
self.display_msg_and_quit( "Command requires at least one filename!", 1 )
if self.delete_tags and self.data_style is None:
diff --git a/comictaggerlib/pageloader.py b/comictaggerlib/pageloader.py
index 0bb0c26..182911a 100644
--- a/comictaggerlib/pageloader.py
+++ b/comictaggerlib/pageloader.py
@@ -22,6 +22,7 @@ from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtCore import pyqtSignal
from comicarchive import ComicArchive
+import utils
"""
This class holds onto a reference of each instance in a list
@@ -66,8 +67,7 @@ class PageLoader( QtCore.QThread ):
return
if image_data is not None:
- img = QtGui.QImage()
- img.loadFromData( image_data )
+ img = utils.getQImageFromData( image_data)
if self.abandoned:
return
diff --git a/comictaggerlib/settings.py b/comictaggerlib/settings.py
index 590ebff..cef49e4 100644
--- a/comictaggerlib/settings.py
+++ b/comictaggerlib/settings.py
@@ -107,6 +107,7 @@ class ComicTaggerSettings:
self.use_series_start_as_volume = False
self.clear_form_before_populating_from_cv = False
self.remove_html_tables = False
+ self.cv_api_key = ""
# CBL Tranform settings
@@ -132,6 +133,7 @@ class ComicTaggerSettings:
self.assume_1_if_no_issue_num = False
self.ignore_leading_numbers_in_filename = False
self.remove_archive_after_successful_match = False
+ self.wait_and_retry_on_rate_limit = False
def __init__(self):
@@ -252,7 +254,8 @@ class ComicTaggerSettings:
self.clear_form_before_populating_from_cv = self.config.getboolean( 'comicvine', 'clear_form_before_populating_from_cv' )
if self.config.has_option('comicvine', 'remove_html_tables'):
self.remove_html_tables = self.config.getboolean( 'comicvine', 'remove_html_tables' )
-
+ if self.config.has_option('comicvine', 'cv_api_key'):
+ self.cv_api_key = self.config.get( 'comicvine', 'cv_api_key' )
if self.config.has_option('cbl_transform', 'assume_lone_credit_is_primary'):
self.assume_lone_credit_is_primary = self.config.getboolean( 'cbl_transform', 'assume_lone_credit_is_primary' )
@@ -292,6 +295,8 @@ class ComicTaggerSettings:
self.ignore_leading_numbers_in_filename = self.config.getboolean( 'autotag', 'ignore_leading_numbers_in_filename' )
if self.config.has_option('autotag', 'remove_archive_after_successful_match'):
self.remove_archive_after_successful_match = self.config.getboolean( 'autotag', 'remove_archive_after_successful_match' )
+ if self.config.has_option('autotag', 'wait_and_retry_on_rate_limit'):
+ self.wait_and_retry_on_rate_limit = self.config.getboolean( 'autotag', 'wait_and_retry_on_rate_limit' )
def save( self ):
@@ -345,6 +350,7 @@ class ComicTaggerSettings:
self.config.set( 'comicvine', 'use_series_start_as_volume', self.use_series_start_as_volume )
self.config.set( 'comicvine', 'clear_form_before_populating_from_cv', self.clear_form_before_populating_from_cv )
self.config.set( 'comicvine', 'remove_html_tables', self.remove_html_tables )
+ self.config.set( 'comicvine', 'cv_api_key', self.cv_api_key )
if not self.config.has_section( 'cbl_transform' ):
self.config.add_section( 'cbl_transform' )
@@ -374,6 +380,7 @@ class ComicTaggerSettings:
self.config.set( 'autotag', 'assume_1_if_no_issue_num', self.assume_1_if_no_issue_num )
self.config.set( 'autotag', 'ignore_leading_numbers_in_filename', self.ignore_leading_numbers_in_filename )
self.config.set( 'autotag', 'remove_archive_after_successful_match', self.remove_archive_after_successful_match )
+ self.config.set( 'autotag', 'wait_and_retry_on_rate_limit', self.wait_and_retry_on_rate_limit )
with codecs.open( self.settings_file, 'wb', 'utf8') as configfile:
self.config.write(configfile)
diff --git a/comictaggerlib/settingswindow.py b/comictaggerlib/settingswindow.py
index 176edbb..727d592 100644
--- a/comictaggerlib/settingswindow.py
+++ b/comictaggerlib/settingswindow.py
@@ -24,6 +24,7 @@ from PyQt4 import QtCore, QtGui, uic
from settings import ComicTaggerSettings
from comicvinecacher import ComicVineCacher
+from comicvinetalker import ComicVineTalker
from imagefetcher import ImageFetcher
import utils
@@ -110,6 +111,7 @@ class SettingsWindow(QtGui.QDialog):
self.btnBrowseUnrar.clicked.connect(self.selectUnrar)
self.btnClearCache.clicked.connect(self.clearCache)
self.btnResetSettings.clicked.connect(self.resetSettings)
+ self.btnTestKey.clicked.connect(self.testAPIKey)
def settingsToForm( self ):
@@ -131,6 +133,7 @@ class SettingsWindow(QtGui.QDialog):
self.cbxClearFormBeforePopulating.setCheckState( QtCore.Qt.Checked)
if self.settings.remove_html_tables:
self.cbxRemoveHtmlTables.setCheckState( QtCore.Qt.Checked)
+ self.leKey.setText( str(self.settings.cv_api_key) )
if self.settings.assume_lone_credit_is_primary:
self.cbxAssumeLoneCreditIsPrimary.setCheckState( QtCore.Qt.Checked)
@@ -185,7 +188,8 @@ class SettingsWindow(QtGui.QDialog):
self.settings.use_series_start_as_volume = self.cbxUseSeriesStartAsVolume.isChecked()
self.settings.clear_form_before_populating_from_cv = self.cbxClearFormBeforePopulating.isChecked()
self.settings.remove_html_tables = self.cbxRemoveHtmlTables.isChecked()
-
+ self.settings.cv_api_key = unicode(self.leKey.text())
+ ComicVineTalker.api_key = self.settings.cv_api_key
self.settings.assume_lone_credit_is_primary = self.cbxAssumeLoneCreditIsPrimary.isChecked()
self.settings.copy_characters_to_tags = self.cbxCopyCharactersToTags.isChecked()
self.settings.copy_teams_to_tags = self.cbxCopyTeamsToTags.isChecked()
@@ -215,6 +219,12 @@ class SettingsWindow(QtGui.QDialog):
ComicVineCacher( ).clearCache()
QtGui.QMessageBox.information(self, self.name, "Cache has been cleared.")
+ def testAPIKey( self ):
+ if ComicVineTalker().testKey( unicode(self.leKey.text()) ):
+ QtGui.QMessageBox.information(self, "API Key Test", "Key is valid!")
+ else:
+ QtGui.QMessageBox.warning(self, "API Key Test", "Key is NOT valid.")
+
def resetSettings( self ):
self.settings.reset()
diff --git a/comictaggerlib/taggerwindow.py b/comictaggerlib/taggerwindow.py
index 4680b3d..84c761f 100644
--- a/comictaggerlib/taggerwindow.py
+++ b/comictaggerlib/taggerwindow.py
@@ -992,11 +992,14 @@ class TaggerWindow( QtGui.QMainWindow):
self.formToMetadata()
try:
- comicVine = ComicVineTalker( )
+ comicVine = ComicVineTalker()
new_metadata = comicVine.fetchIssueData( selector.volume_id, selector.issue_number, self.settings )
- except ComicVineTalkerException:
+ except ComicVineTalkerException as e:
QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.critical(self, self.tr("Network Issue"), self.tr("Could not connect to ComicVine to get issue details!"))
+ if e.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 ComicVine to get issue details.!"))
else:
QtGui.QApplication.restoreOverrideCursor()
if new_metadata is not None:
@@ -1554,7 +1557,9 @@ class TaggerWindow( QtGui.QMainWindow):
QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
try:
- cv_md = ComicVineTalker().fetchIssueData( match['volume_id'], match['issue_number'], self.settings )
+ comicVine = ComicVineTalker( )
+ comicVine.wait_for_rate_limit = self.settings.wait_and_retry_on_rate_limit
+ cv_md = comicVine.fetchIssueData( match['volume_id'], match['issue_number'], self.settings )
except ComicVineTalkerException:
print "Network error while getting issue details. Save aborted"
@@ -1601,6 +1606,7 @@ class TaggerWindow( QtGui.QMainWindow):
md.issue = "1"
ii.setAdditionalMetadata( md )
ii.onlyUseAdditionalMetaData = True
+ ii.waitAndRetryOnRateLimit = dlg.waitAndRetryOnRateLimit
ii.setOutputFunction( self.autoTagLog )
ii.cover_page_index = md.getCoverPageIndexList()[0]
ii.setCoverURLCallback( self.atprogdialog.setTestImage )
@@ -1682,6 +1688,7 @@ class TaggerWindow( QtGui.QMainWindow):
atstartdlg = AutoTagStartWindow( self, self.settings,
self.tr("You have selected {0} archive(s) to automatically identify and write {1} tags to.\n\n".format(len(ca_list), MetaDataStyle.name[style]) +
"Please choose options below, and select OK to Auto-Tag.\n" ))
+
atstartdlg.adjustSize( )
atstartdlg.setModal( True )
if not atstartdlg.exec_():
diff --git a/comictaggerlib/ui/autotagstartwindow.ui b/comictaggerlib/ui/autotagstartwindow.ui
index 2ddb8e9..78bc088 100644
--- a/comictaggerlib/ui/autotagstartwindow.ui
+++ b/comictaggerlib/ui/autotagstartwindow.ui
@@ -9,8 +9,8 @@
0
0
- 607
- 319
+ 497
+ 378
@@ -25,183 +25,180 @@
false
-
+
-
-
-
-
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ true
+
+
+
+ -
+
+
-
+
-
+
0
0
-
-
-
- true
+ Specify series search string for all selected archives
- -
-
-
- QLayout::SetFixedSize
+
-
+
+
+
+ 0
+ 0
+
-
- QFormLayout::AllNonFixedFieldsGrow
+
+ Save on low confidence match
-
-
-
-
-
- 0
- 0
-
-
-
- Save on low confidence match
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Don't use publication year in indentification process
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- If no issue number, assume "1"
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Ignore leading (sequence) numbers in filename
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Remove archives from list after successful tagging
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Specify series search string for all selected archives
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 40
- 0
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 50
- 16777215
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Adjust Name Length Match Tolerance:
-
-
-
-
+
- -
-
-
- Qt::Horizontal
+
-
+
+
+
+ 0
+ 0
+
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+ Ignore leading (sequence) numbers in filename
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Remove archives from list after successful tagging
+
+
+
+ -
+
+
+ Wait and retry when Comic Vine rate limit is exceeded
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Don't use publication year in indentification process
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ If no issue number, assume "1"
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 16777215
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Adjust Name Length Match Tolerance:
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 40
+ 0
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
diff --git a/comictaggerlib/ui/settingswindow.ui b/comictaggerlib/ui/settingswindow.ui
index c8d0765..da5886f 100644
--- a/comictaggerlib/ui/settingswindow.ui
+++ b/comictaggerlib/ui/settingswindow.ui
@@ -6,8 +6,8 @@
0
0
- 674
- 428
+ 702
+ 432
@@ -21,6 +21,12 @@
-
+
+
+ 0
+ 0
+
+
0
@@ -336,45 +342,156 @@
Comic Vine
-
-
-
- 30
- 30
- 251
- 25
-
-
-
- Use Series Start Date as Volume
-
-
-
-
-
- 30
- 50
- 341
- 25
-
-
-
- Clear Form Before Importing Comic Vine data
-
-
-
-
-
- 30
- 70
- 351
- 25
-
-
-
- Remove HTML tables from CV summary field
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
-
+
+
-
+
+
+ Use Series Start Date as Volume
+
+
+
+ -
+
+
+ Clear Form Before Importing Comic Vine data
+
+
+
+ -
+
+
+ Remove HTML tables from CV summary field
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 120
+ 0
+
+
+
+
+ 200
+ 16777215
+
+
+
+ Comic Vine API Key
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>A personal API key from <a href="http://www.comicvine.com/api/"><span style=" text-decoration: underline; color:#0000ff;">Comic Vine</span></a> is recommended in order to search for tag data. Login (or create a new account) there to get your key, and enter it below.</p></body></html>
+
+
+ Qt::RichText
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+
+ true
+
+
+ true
+
+
+ Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse
+
+
+
+ -
+
+
+ Tesk Key
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
diff --git a/comictaggerlib/utils.py b/comictaggerlib/utils.py
index 2508f29..4d9b529 100644
--- a/comictaggerlib/utils.py
+++ b/comictaggerlib/utils.py
@@ -25,13 +25,14 @@ import re
import platform
import locale
import codecs
+from settings import ComicTaggerSettings
class UtilsVars:
already_fixed_encoding = False
def get_actual_preferred_encoding():
preferred_encoding = locale.getpreferredencoding()
- if getattr(sys, 'frozen', None) and platform.system() == "Darwin":
+ if platform.system() == "Darwin":
preferred_encoding = "utf-8"
return preferred_encoding
@@ -629,4 +630,34 @@ if qt_available:
# And vertical position the same, but with the height dimensions
vpos = ( main_window_size.height() - window.height() ) / 2
# And the move call repositions the window
- window.move(hpos + main_window_size.left(), vpos + main_window_size.top())
+ window.move(hpos + main_window_size.left(), vpos + main_window_size.top())
+
+ try:
+ from PIL import Image
+ from PIL import WebPImagePlugin
+ import StringIO
+ pil_available = True
+ except ImportError:
+ pil_available = False
+
+ def getQImageFromData(image_data):
+ img = QtGui.QImage()
+ success = img.loadFromData( image_data )
+ if not success:
+ try:
+ if pil_available:
+ # Qt doesn't understand the format, but maybe PIL does
+ # so try to convert the image data to uncompressed tiff format
+ im = Image.open(StringIO.StringIO(image_data))
+ output = StringIO.StringIO()
+ im.save(output, format="TIFF")
+ img.loadFromData( output.getvalue() )
+ success = True
+ except Exception as e:
+ pass
+ # if still nothing, go with default image
+ if not success:
+ img.load(ComicTaggerSettings.getGraphic('nocover.png'))
+ return img
+
+
diff --git a/comictaggerlib/volumeselectionwindow.py b/comictaggerlib/volumeselectionwindow.py
index 4231741..c421029 100644
--- a/comictaggerlib/volumeselectionwindow.py
+++ b/comictaggerlib/volumeselectionwindow.py
@@ -46,15 +46,18 @@ class SearchThread( QtCore.QThread):
QtCore.QThread.__init__(self)
self.series_name = series_name
self.refresh = refresh
+ self.error_code = None
def run(self):
- comicVine = ComicVineTalker( )
+ comicVine = ComicVineTalker()
try:
self.cv_error = False
self.cv_search_results = comicVine.searchForSeries( self.series_name, callback=self.prog_callback, refresh_cache=self.refresh )
- except ComicVineTalkerException:
+ except ComicVineTalkerException as e:
self.cv_search_results = []
self.cv_error = True
+ self.error_code = e.code
+
finally:
self.searchComplete.emit()
@@ -293,7 +296,10 @@ class VolumeSelectionWindow(QtGui.QDialog):
def searchComplete( self ):
self.progdialog.accept()
if self.search_thread.cv_error:
- QtGui.QMessageBox.critical(self, self.tr("Network Issue"), self.tr("Could not connect to ComicVine to search for series!"))
+ 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 ComicVine to search for series!"))
return
self.cv_search_results = self.search_thread.cv_search_results