From fb6d6a42b97dfe8b2484dddc268ce2f81526ecb0 Mon Sep 17 00:00:00 2001 From: "beville@gmail.com" Date: Mon, 19 Nov 2012 03:55:40 +0000 Subject: [PATCH] Got basic tag save via CLI working git-svn-id: http://comictagger.googlecode.com/svn/trunk@59 6c5673fe-1810-88d6-992b-cd32ca31540c --- comicarchive.py | 2 +- comicvinetalker.py | 3 +- genericmetadata.py | 60 ++++++++++++++++++- options.py | 14 +++-- tagger.py | 142 ++++++++++++++++++++++++++++++++++----------- todo.txt | 16 +++-- 6 files changed, 186 insertions(+), 51 deletions(-) diff --git a/comicarchive.py b/comicarchive.py index 445b5c2..4f96545 100644 --- a/comicarchive.py +++ b/comicarchive.py @@ -561,5 +561,5 @@ class ComicArchive: metadata.publicationYear = fnp.year metadata.isEmpty = False - + return metadata diff --git a/comicvinetalker.py b/comicvinetalker.py index 75efc84..a4bc584 100644 --- a/comicvinetalker.py +++ b/comicvinetalker.py @@ -36,7 +36,7 @@ from genericmetadata import GenericMetadata class ComicVineTalker(QObject): - def __init__(self, api_key): + def __init__(self, api_key=""): QObject.__init__(self) # key that is registered to comictagger @@ -142,7 +142,6 @@ class ComicVineTalker(QObject): volume_url = "http://api.comicvine.com/volume/" + str(series_id) + "/?api_key=" + self.api_key + "&format=json" - #print "search_url = : ", volume_url resp = urllib2.urlopen(volume_url) content = resp.read() diff --git a/genericmetadata.py b/genericmetadata.py index 74476b1..b6df2b9 100644 --- a/genericmetadata.py +++ b/genericmetadata.py @@ -97,6 +97,59 @@ class GenericMetadata: self.tags = list() self.pages = list() + def overlay( self, new_md ): + # Overlay a metadata object on this one + # that is, when the new object has non-None + # values, over-write them to this one + + def assign( cur, new ): + if new is not None: + setattr(self, cur, new) + + if not new_md.isEmpty: + self.isEmpty = False + + assign( 'series', new_md.series ) + assign( "issueNumber", new_md.issueNumber ) + assign( "issueCount", new_md.issueCount ) + assign( "title", new_md.title ) + assign( "publisher", new_md.publisher ) + assign( "publicationMonth", new_md.publicationMonth ) + assign( "publicationYear", new_md.publicationYear ) + assign( "volumeNumber", new_md.volumeNumber ) + assign( "volumeCount", new_md.volumeCount ) + assign( "genre", new_md.genre ) + assign( "language", new_md.language ) + assign( "country", new_md.country ) + assign( "alternateSeries", new_md.criticalRating ) + assign( "alt. series", new_md.alternateSeries ) + assign( "alternateNumber", new_md.alternateNumber ) + assign( "alternateCount", new_md.alternateCount ) + assign( "imprint", new_md.imprint ) + assign( "web", new_md.webLink ) + assign( "format", new_md.format ) + assign( "manga", new_md.manga ) + assign( "blackAndWhite", new_md.blackAndWhite ) + assign( "maturityRating", new_md.maturityRating ) + assign( "scanInfo", new_md.scanInfo ) + assign( "scanInfo", new_md.scanInfo ) + assign( "scanInfo", new_md.scanInfo ) + assign( "characters", new_md.characters ) + assign( "teams", new_md.teams ) + assign( "locations", new_md.locations ) + assign( "comments", new_md.comments ) + assign( "notes", new_md.notes ) + + # TODO + # not sure if the tags, credits, and pages should broken down, or treated + # as whole lists.... For now, go the easy route, where any overlay + # value wipes out the whole list + + assign( "tags", new_md.tags ) + assign( "credits", new_md.credits ) + assign( "pages", new_md.pages ) + + def addCredit( self, person, role, primary = False ): credit = dict() @@ -114,7 +167,7 @@ class GenericMetadata: return "No metadata" def add( tag, val ): - if val is not None and str(val) != "": + if val is not None and u"{0}".format(val) != "": vals.append( (tag, val) ) add( "series", self.series ) @@ -148,10 +201,10 @@ class GenericMetadata: add( "comments", self.comments ) add( "notes", self.notes ) add( "tags", utils.listToString( self.tags ) ) + for c in self.credits: add( "credit", c['role']+": "+c['person'] ) - # find the longest field name flen = 0 for i in vals: @@ -160,7 +213,8 @@ class GenericMetadata: #format the data nicely outstr = "" + fmt_str = u"{0: <" + str(flen) + "}: {1}\n" for i in vals: - outstr += ("{0: <" + str(flen) + "}: {1}\n").format( i[0], i[1] ) + outstr += fmt_str.format( i[0], i[1] ) return outstr diff --git a/options.py b/options.py index 1cdc813..8695d5a 100644 --- a/options.py +++ b/options.py @@ -56,7 +56,7 @@ If no options are given, {0} will run in windowed mode year -o, --online Search online and attempt to identify file using existing metadata and images in archive. May be used - in conjuntion with -p and -m + in conjuntion with -f and -m -m, --metadata=LIST Explicity define some tags to be used as a list ....TBD........ ....TBD........ @@ -72,11 +72,11 @@ If no options are given, {0} will run in windowed mode self.no_gui = False self.filename = None self.verbose = False - self.md_settings = None + self.metadata = None self.print_tags = False self.delete_tags = False self.search_online = False - self.dryrun = True # keep this true for now! + self.dryrun = False self.save_tags = False self.parse_filename = False self.rename_file = False @@ -87,10 +87,12 @@ If no options are given, {0} will run in windowed mode print( msg ) print self.help_text.format(appname) sys.exit(code) - + + def parseMetadataFromString( self, mdstr ): + print "TBD!!!!!!!!!!!!!!!!!!!!!" + return None def parseCmdLineArgs(self): - # mac no likey this from .app bundle if platform.system() == "Darwin" and getattr(sys, 'frozen', None): @@ -121,7 +123,7 @@ If no options are given, {0} will run in windowed mode if o in ("-n", "--dryrun"): self.dryrun = True if o in ("-m", "--metadata"): - self.md_settings = a + self.metadata = self.parseMetadataFromString(a) if o in ("-s", "--save"): self.save_tags = True if o in ("-r", "--rename"): diff --git a/tagger.py b/tagger.py index 13bac9a..6a6621b 100755 --- a/tagger.py +++ b/tagger.py @@ -33,6 +33,8 @@ from taggerwindow import TaggerWindow from options import Options, MetaDataStyle from comicarchive import ComicArchive from issueidentifier import IssueIdentifier +from genericmetadata import GenericMetadata +from comicvinetalker import ComicVineTalker import utils @@ -49,6 +51,11 @@ def cli_mode( opts, settings ): if not ca.seemsToBeAComicArchive(): print "Sorry, but "+ opts.filename + " is not a comic archive!" return + + if not ca.isWritable() and ( opts.delete_tags or opts.save_tags or opts.rename_file ): + print "This archive is not writable." + return + cix = False cbi = False @@ -81,61 +88,128 @@ def cli_mode( opts, settings ): if opts.data_style is None or opts.data_style == MetaDataStyle.CIX: if cix: print "------ComicRack tags--------" - print ca.readCIX() + print u"{0}".format(ca.readCIX()) if opts.data_style is None or opts.data_style == MetaDataStyle.CBI: if cbi: print "------ComicBookLover tags--------" - print ca.readCBI() + print u"{0}".format(ca.readCBI()) - elif opts.delete_tags: - if not ca.isWritable(): - print "This archive is not writable." - return - + elif opts.delete_tags: if opts.data_style == MetaDataStyle.CIX: if cix: - ca.removeCIX() - print "Removed ComicRack tags." + if not opts.dryrun: + ca.removeCIX() + print "Removed ComicRack tags." + else: + print "dry-run. ComicRack tags not removed" else: print "This archive doesn't have ComicRack tags." if opts.data_style == MetaDataStyle.CBI: if cbi: - ca.removeCBI() - print "Removed ComicBookLover tags." + if not opts.dryrun: + ca.removeCBI() + print "Removed ComicBookLover tags." + else: + print "dry-run. ComicBookLover tags not removed" else: print "This archive doesn't have ComicBookLover tags." - #elif opt.rename: - # print "Gonna rename file" - elif opts.save_tags: - if opts.data_style == MetaDataStyle.CIX: - print "Gonna save ComicRack tags" - if opts.data_style == MetaDataStyle.CBI: - print "Gonna save ComicBookLover tags" - - """ - ii = IssueIdentifier( ca, settings.cv_api_key ) - matches = ii.search() + # OK we're gonna do a save of some new data + md = GenericMetadata() - if len(matches) == 1: + # First read in existing data, if it's there + if opts.data_style == MetaDataStyle.CIX and cix: + md = ca.readCIX() + elif opts.data_style == MetaDataStyle.CBI and cbi: + md = ca.readCBI() + + # now, overlay the new data onto the old, in order + + if opts.parse_filename: + md.overlay( ca.metadataFromFilename() ) + + if opts.metadata is not None: + md.overlay( opts.metadata ) + + + # finally, search online + if opts.search_online: + + ii = IssueIdentifier( ca, "" ) + + if md is None or md.isEmpty: + print "No metadata given to search online with!" + return + + def myoutput( text ): + if opts.verbose: + IssueIdentifier.defaultWriteOutput( text ) + + # use our overlayed MD struct to search + ii.setAdditionalMetadata( md ) + ii.onlyUseAdditionalMetaData = True + ii.setOutputFunction( myoutput ) + matches = ii.search() + + result = ii.search_result + + found_match = False + choices = False + low_confidence = False + + if result == ii.ResultNoMatches: + pass + elif result == ii.ResultFoundMatchButBadCoverScore: + low_confidence = False + found_match = True + elif result == ii.ResultFoundMatchButNotFirstPage : + found_match = True + elif result == ii.ResultMultipleMatchesWithBadImageScores: + low_confidence = False + choices = True + elif result == ii.ResultOneGoodMatch: + found_match = True + elif result == ii.ResultMultipleGoodMatches: + choices = True + + if choices: + print "Online search: Multiple matches. Save aborted" + return + if low_confidence: + print "Online search: Low confidence match. Save aborted" + return + if not found_match: + print "Online search: No match found. Save aborted" + return + + # we got here, so we have a single match # now get the particular issue data - metadata = comicVine.fetchIssueData( match[0]['series'], match[0]['issue_number'] ) - - # write out the new data - ca.writeMetadata( metadata, opts.data_style ) - - elif len(matches) == 0: - pass + cv_md = ComicVineTalker().fetchIssueData( matches[0]['volume_id'], matches[0]['issue_number'] ) + + md.overlay( cv_md ) + # ok, done building our metadata. time to save - elif len(matches) == 0: - # print match options, with CV issue ID's - pass - """ + #HACK + opts.dryrun = True + #HACK + + if not opts.dryrun: + # write out the new data + ca.writeMetadata( md, opts.data_style ) + else: + print "dry-run option was set, so nothing was written, but here is the final set of tags:" + print u"{0}".format(md) + + elif opt.rename_file: + print "File renaming TBD" + + + #----------------------------- def main(): diff --git a/todo.txt b/todo.txt index 3d51762..c74fab1 100644 --- a/todo.txt +++ b/todo.txt @@ -2,8 +2,14 @@ Features ---------------- CLI - rename - save + save log + abort flag + explicit metadata settings option format + just series, issue, year?? + multiple files? + verbose settings for identifier + interactive for choices option? + --- or defer choices to end, by keeping special log of those files Settings/Preferences Dialog Remove API Key @@ -34,13 +40,11 @@ Bugs SERIOUS BUG: rebuilding zips! http://stackoverflow.com/questions/11578443/trigger-io-errno-18-cross-device-link -Test ComicRack android - OSX: toolbar weird unrar complaints Page browser sizing - Override curson is not beachball + Override cursor is not beachball Other settings possibilities: Last tag style @@ -50,6 +54,8 @@ Other settings possibilities: Filename parsing: Rework how series name is separated from issue +Test ComicRack android + Form type validation Ints vs strings for month, year. etc Check all HTTP responses for errors