"""A class to encapsulate CoMet data""" # Copyright 2012-2014 Anthony Beville # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import xml.etree.ElementTree as ET from . import utils from .genericmetadata import GenericMetadata # from datetime import datetime # from pprint import pprint # import zipfile class CoMet: writer_synonyms = ["writer", "plotter", "scripter"] penciller_synonyms = ["artist", "penciller", "penciler", "breakdowns"] inker_synonyms = ["inker", "artist", "finishes"] colorist_synonyms = ["colorist", "colourist", "colorer", "colourer"] letterer_synonyms = ["letterer"] cover_synonyms = ["cover", "covers", "coverartist", "cover artist"] editor_synonyms = ["editor"] def metadataFromString(self, string): tree = ET.ElementTree(ET.fromstring(string)) return self.convertXMLToMetadata(tree) def stringFromMetadata(self, metadata): header = '\n' tree = self.convertMetadataToXML(self, metadata) return header + ET.tostring(tree.getroot()) def indent(self, elem, level=0): # for making the XML output readable i = "\n" + level * " " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: self.indent(elem, level + 1) if not elem.tail or not elem.tail.strip(): elem.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i def convertMetadataToXML(self, filename, metadata): # shorthand for the metadata md = metadata # build a tree structure root = ET.Element("comet") root.attrib["xmlns:comet"] = "http://www.denvog.com/comet/" root.attrib["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" root.attrib["xsi:schemaLocation"] = "http://www.denvog.com http://www.denvog.com/comet/comet.xsd" # helper func def assign(comet_entry, md_entry): if md_entry is not None: ET.SubElement(root, comet_entry).text = "{0}".format(md_entry) # title is manditory if md.title is None: md.title = "" assign("title", md.title) assign("series", md.series) assign("issue", md.issue) # must be int?? assign("volume", md.volume) assign("description", md.comments) assign("publisher", md.publisher) assign("pages", md.pageCount) assign("format", md.format) assign("language", md.language) assign("rating", md.maturityRating) assign("price", md.price) assign("isVersionOf", md.isVersionOf) assign("rights", md.rights) assign("identifier", md.identifier) assign("lastMark", md.lastMark) assign("genre", md.genre) # TODO repeatable if md.characters is not None: char_list = [c.strip() for c in md.characters.split(",")] for c in char_list: assign("character", c) if md.manga is not None and md.manga == "YesAndRightToLeft": assign("readingDirection", "rtl") date_str = "" if md.year is not None: date_str = str(md.year).zfill(4) if md.month is not None: date_str += "-" + str(md.month).zfill(2) assign("date", date_str) assign("coverImage", md.coverImage) # need to specially process the credits, since they are structured # differently than CIX credit_writer_list = list() credit_penciller_list = list() credit_inker_list = list() credit_colorist_list = list() credit_letterer_list = list() credit_cover_list = list() credit_editor_list = list() # loop thru credits, and build a list for each role that CoMet supports for credit in metadata.credits: if credit["role"].lower() in set(self.writer_synonyms): ET.SubElement(root, "writer").text = "{0}".format(credit["person"]) if credit["role"].lower() in set(self.penciller_synonyms): ET.SubElement(root, "penciller").text = "{0}".format(credit["person"]) if credit["role"].lower() in set(self.inker_synonyms): ET.SubElement(root, "inker").text = "{0}".format(credit["person"]) if credit["role"].lower() in set(self.colorist_synonyms): ET.SubElement(root, "colorist").text = "{0}".format(credit["person"]) if credit["role"].lower() in set(self.letterer_synonyms): ET.SubElement(root, "letterer").text = "{0}".format(credit["person"]) if credit["role"].lower() in set(self.cover_synonyms): ET.SubElement(root, "coverDesigner").text = "{0}".format(credit["person"]) if credit["role"].lower() in set(self.editor_synonyms): ET.SubElement(root, "editor").text = "{0}".format(credit["person"]) # self pretty-print self.indent(root) # wrap it in an ElementTree instance, and save as XML tree = ET.ElementTree(root) return tree def convertXMLToMetadata(self, tree): root = tree.getroot() if root.tag != "comet": raise 1 return None metadata = GenericMetadata() md = metadata # Helper function def xlate(tag): node = root.find(tag) if node is not None: return node.text else: return None md.series = xlate("series") md.title = xlate("title") md.issue = xlate("issue") md.volume = xlate("volume") md.comments = xlate("description") md.publisher = xlate("publisher") md.language = xlate("language") md.format = xlate("format") md.pageCount = xlate("pages") md.maturityRating = xlate("rating") md.price = xlate("price") md.isVersionOf = xlate("isVersionOf") md.rights = xlate("rights") md.identifier = xlate("identifier") md.lastMark = xlate("lastMark") md.genre = xlate("genre") # TODO - repeatable field date = xlate("date") if date is not None: parts = date.split("-") if len(parts) > 0: md.year = parts[0] if len(parts) > 1: md.month = parts[1] md.coverImage = xlate("coverImage") readingDirection = xlate("readingDirection") if readingDirection is not None and readingDirection == "rtl": md.manga = "YesAndRightToLeft" # loop for character tags char_list = [] for n in root: if n.tag == "character": char_list.append(n.text.strip()) md.characters = utils.listToString(char_list) # Now extract the credit info for n in root: if n.tag == "writer" or n.tag == "penciller" or n.tag == "inker" or n.tag == "colorist" or n.tag == "letterer" or n.tag == "editor": metadata.addCredit(n.text.strip(), n.tag.title()) if n.tag == "coverDesigner": metadata.addCredit(n.text.strip(), "Cover") metadata.isEmpty = False return metadata # verify that the string actually contains CoMet data in XML format def validateString(self, string): try: tree = ET.ElementTree(ET.fromstring(string)) root = tree.getroot() if root.tag != "comet": raise Exception except: return False return True def writeToExternalFile(self, filename, metadata): tree = self.convertMetadataToXML(self, metadata) # ET.dump(tree) tree.write(filename, encoding="utf-8") def readFromExternalFile(self, filename): tree = ET.parse(filename) return self.convertXMLToMetadata(tree)