fixes for webp, api key handling, and CV rate limit

git-svn-id: http://comictagger.googlecode.com/svn/trunk@734 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
beville 2014-06-13 06:26:44 +00:00
parent 0c146bb245
commit 301ff084f1
19 changed files with 593 additions and 350 deletions

View File

@ -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 = (
""" <html>The <b>Name Length Match Tolerance</b> 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())

View File

@ -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

View File

@ -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

View File

@ -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']

View File

@ -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!"

View File

@ -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"

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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_():

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>319</height>
<width>497</width>
<height>378</height>
</rect>
</property>
<property name="sizePolicy">
@ -25,183 +25,180 @@
<property name="modal">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="0">
<widget class="QCheckBox" name="cbxSpecifySearchString">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
<string>Specify series search string for all selected archives</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
<item row="0" column="0">
<widget class="QCheckBox" name="cbxSaveOnLowConfidence">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
<property name="text">
<string>Save on low confidence match</string>
</property>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="cbxSaveOnLowConfidence">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Save on low confidence match</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="cbxDontUseYear">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Don't use publication year in indentification process</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="cbxAssumeIssueOne">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>If no issue number, assume &quot;1&quot;</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="cbxIgnoreLeadingDigitsInFilename">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Ignore leading (sequence) numbers in filename</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="cbxRemoveAfterSuccess">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Remove archives from list after successful tagging</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="cbxSpecifySearchString">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Specify series search string for all selected archives</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="leSearchString">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="leNameLengthMatchTolerance">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Adjust Name Length Match Tolerance:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="4" column="0">
<widget class="QCheckBox" name="cbxIgnoreLeadingDigitsInFilename">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<property name="text">
<string>Ignore leading (sequence) numbers in filename</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="cbxRemoveAfterSuccess">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Remove archives from list after successful tagging</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="cbxWaitForRateLimit">
<property name="text">
<string>Wait and retry when Comic Vine rate limit is exceeded</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="cbxDontUseYear">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Don't use publication year in indentification process</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="cbxAssumeIssueOne">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>If no issue number, assume &quot;1&quot;</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLineEdit" name="leNameLengthMatchTolerance">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLineEdit" name="leSearchString">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Adjust Name Length Match Tolerance:</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>674</width>
<height>428</height>
<width>702</width>
<height>432</height>
</rect>
</property>
<property name="windowTitle">
@ -21,6 +21,12 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
@ -336,45 +342,156 @@
<attribute name="title">
<string>Comic Vine</string>
</attribute>
<widget class="QCheckBox" name="cbxUseSeriesStartAsVolume">
<property name="geometry">
<rect>
<x>30</x>
<y>30</y>
<width>251</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>Use Series Start Date as Volume</string>
</property>
</widget>
<widget class="QCheckBox" name="cbxClearFormBeforePopulating">
<property name="geometry">
<rect>
<x>30</x>
<y>50</y>
<width>341</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>Clear Form Before Importing Comic Vine data</string>
</property>
</widget>
<widget class="QCheckBox" name="cbxRemoveHtmlTables">
<property name="geometry">
<rect>
<x>30</x>
<y>70</y>
<width>351</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>Remove HTML tables from CV summary field</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="grpBoxCVTop">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="cbxUseSeriesStartAsVolume">
<property name="text">
<string>Use Series Start Date as Volume</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbxClearFormBeforePopulating">
<property name="text">
<string>Clear Form Before Importing Comic Vine data</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbxRemoveHtmlTables">
<property name="text">
<string>Remove HTML tables from CV summary field</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="grpBoxKey">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_8">
<item row="1" column="1">
<widget class="QLineEdit" name="leKey">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Comic Vine API Key</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="lblKeyHelp">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A personal API key from &lt;a href=&quot;http://www.comicvine.com/api/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Comic Vine&lt;/span&gt;&lt;/a&gt; is recommended in order to search for tag data. Login (or create a new account) there to get your key, and enter it below.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnTestKey">
<property name="text">
<string>Tesk Key</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">

View File

@ -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

View File

@ -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