2015-02-21 18:30:32 -08:00
|
|
|
"""A class to encapsulate CoMet data"""
|
2015-02-16 04:27:21 -08:00
|
|
|
|
2015-02-21 18:30:32 -08:00
|
|
|
# Copyright 2012-2014 Anthony Beville
|
2015-02-16 04:27:21 -08:00
|
|
|
|
2015-02-21 18:30:32 -08:00
|
|
|
# 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
|
2015-02-16 04:27:21 -08:00
|
|
|
|
2015-02-21 18:30:32 -08:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2015-02-16 04:27:21 -08:00
|
|
|
|
2015-02-21 18:30:32 -08:00
|
|
|
# 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.
|
2015-02-16 04:27:21 -08:00
|
|
|
|
|
|
|
import xml.etree.ElementTree as ET
|
2015-02-21 18:30:32 -08:00
|
|
|
|
2018-09-19 13:05:39 -07:00
|
|
|
from . import utils
|
2020-07-06 16:11:15 -07:00
|
|
|
from .genericmetadata import GenericMetadata
|
|
|
|
|
|
|
|
# from datetime import datetime
|
|
|
|
# from pprint import pprint
|
|
|
|
# import zipfile
|
2015-02-16 04:27:21 -08:00
|
|
|
|
2015-02-21 18:30:32 -08:00
|
|
|
|
2015-02-16 04:27:21 -08:00
|
|
|
class CoMet:
|
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
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"]
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
def metadataFromString(self, string):
|
|
|
|
|
|
|
|
tree = ET.ElementTree(ET.fromstring(string))
|
|
|
|
return self.convertXMLToMetadata(tree)
|
|
|
|
|
|
|
|
def stringFromMetadata(self, metadata):
|
|
|
|
|
|
|
|
header = '<?xml version="1.0" encoding="UTF-8"?>\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")
|
2020-07-06 16:11:15 -07:00
|
|
|
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"
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
# helper func
|
|
|
|
def assign(comet_entry, md_entry):
|
|
|
|
if md_entry is not None:
|
2018-09-19 13:05:39 -07:00
|
|
|
ET.SubElement(root, comet_entry).text = "{0}".format(md_entry)
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
# title is manditory
|
|
|
|
if md.title is None:
|
|
|
|
md.title = ""
|
2020-07-06 16:11:15 -07:00
|
|
|
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
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
if md.characters is not None:
|
2020-07-06 16:11:15 -07:00
|
|
|
char_list = [c.strip() for c in md.characters.split(",")]
|
2015-02-21 18:30:32 -08:00
|
|
|
for c in char_list:
|
2020-07-06 16:11:15 -07:00
|
|
|
assign("character", c)
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
if md.manga is not None and md.manga == "YesAndRightToLeft":
|
2020-07-06 16:11:15 -07:00
|
|
|
assign("readingDirection", "rtl")
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
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)
|
2020-07-06 16:11:15 -07:00
|
|
|
assign("date", date_str)
|
2015-02-21 18:30:32 -08:00
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
assign("coverImage", md.coverImage)
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
# 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:
|
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
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"])
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
# 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()
|
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
if root.tag != "comet":
|
2015-02-21 18:30:32 -08:00
|
|
|
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
|
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
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")
|
2015-02-21 18:30:32 -08:00
|
|
|
if date is not None:
|
2020-07-06 16:11:15 -07:00
|
|
|
parts = date.split("-")
|
2015-02-21 18:30:32 -08:00
|
|
|
if len(parts) > 0:
|
|
|
|
md.year = parts[0]
|
|
|
|
if len(parts) > 1:
|
|
|
|
md.month = parts[1]
|
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
md.coverImage = xlate("coverImage")
|
2015-02-21 18:30:32 -08:00
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
readingDirection = xlate("readingDirection")
|
2015-02-21 18:30:32 -08:00
|
|
|
if readingDirection is not None and readingDirection == "rtl":
|
|
|
|
md.manga = "YesAndRightToLeft"
|
|
|
|
|
|
|
|
# loop for character tags
|
|
|
|
char_list = []
|
|
|
|
for n in root:
|
2020-07-06 16:11:15 -07:00
|
|
|
if n.tag == "character":
|
2015-02-21 18:30:32 -08:00
|
|
|
char_list.append(n.text.strip())
|
|
|
|
md.characters = utils.listToString(char_list)
|
|
|
|
|
|
|
|
# Now extract the credit info
|
|
|
|
for n in root:
|
2020-07-06 16:11:15 -07:00
|
|
|
if n.tag == "writer" or n.tag == "penciller" or n.tag == "inker" or n.tag == "colorist" or n.tag == "letterer" or n.tag == "editor":
|
2015-02-21 18:30:32 -08:00
|
|
|
metadata.addCredit(n.text.strip(), n.tag.title())
|
|
|
|
|
2020-07-06 16:11:15 -07:00
|
|
|
if n.tag == "coverDesigner":
|
2015-02-21 18:30:32 -08:00
|
|
|
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()
|
2020-07-06 16:11:15 -07:00
|
|
|
if root.tag != "comet":
|
2015-02-21 18:30:32 -08:00
|
|
|
raise Exception
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def writeToExternalFile(self, filename, metadata):
|
|
|
|
|
|
|
|
tree = self.convertMetadataToXML(self, metadata)
|
|
|
|
# ET.dump(tree)
|
2020-07-06 16:11:15 -07:00
|
|
|
tree.write(filename, encoding="utf-8")
|
2015-02-21 18:30:32 -08:00
|
|
|
|
|
|
|
def readFromExternalFile(self, filename):
|
|
|
|
|
|
|
|
tree = ET.parse(filename)
|
|
|
|
return self.convertXMLToMetadata(tree)
|