From 02e92ca8712967eeb8f5d8580c9a758aef1e18ad Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 13 Jan 2010 13:45:58 -0700 Subject: [PATCH] ... --- src/calibre/library/catalog.py | 209 +++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 src/calibre/library/catalog.py diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py new file mode 100644 index 0000000000..8efb36a88f --- /dev/null +++ b/src/calibre/library/catalog.py @@ -0,0 +1,209 @@ +import os + +from calibre.customize import CatalogPlugin + +class CSV_XML(CatalogPlugin): + 'CSV/XML catalog generator' + + from collections import namedtuple + + Option = namedtuple('Option', 'option, default, dest, help') + + name = 'Catalog_CSV_XML' + description = 'CSV/XML catalog generator' + supported_platforms = ['windows', 'osx', 'linux'] + author = 'Greg Riker' + version = (1, 0, 0) + file_types = set(['csv','xml']) + + cli_options = [ + Option('--fields', + default = 'all', + dest = 'fields', + help = _('The fields to output when cataloging books in the ' + 'database. Should be a comma-separated list of fields.\n' + 'Available fields: all, author_sort, authors, comments, ' + 'cover, formats, id, isbn, pubdate, publisher, rating, ' + 'series_index, series, size, tags, timestamp, title, uuid.\n' + "Default: '%default'\n" + "Applies to: CSV, XML output formats")), + + Option('--sort-by', + default = 'id', + dest = 'sort_by', + help = _('Output field to sort on.\n' + 'Available fields: author_sort, id, rating, size, timestamp, title.\n' + "Default: '%default'\n" + "Applies to: CSV, XML output formats"))] + + def run(self, path_to_output, opts, db): + from calibre.utils.logging import Log + + log = Log() + self.fmt = path_to_output[path_to_output.rfind('.') + 1:] + if opts.verbose: + log("%s:run" % self.name) + log(" path_to_output: %s" % path_to_output) + log(" Output format: %s" % self.fmt) + + # Display opts + opts_dict = vars(opts) + keys = opts_dict.keys() + keys.sort() + log(" opts:") + for key in keys: + log(" %s: %s" % (key, opts_dict[key])) + + # Get the sorted, filtered database as a dictionary + data = self.search_sort_db_as_dict(db, opts) + + if not len(data): + log.error("\nNo matching database entries for search criteria '%s'" % opts.search_text) + raise SystemExit(1) + + # Get the requested output fields as a list + fields = self.get_output_fields(opts) + + if self.fmt == 'csv': + outfile = open(path_to_output, 'w') + + # Output the field headers + outfile.write('%s\n' % ','.join(fields)) + + # Output the entry fields + for entry in data: + outstr = '' + for (x, field) in enumerate(fields): + item = entry[field] + if field in ['authors','tags','formats']: + item = ', '.join(item) + if x < len(fields) - 1: + if item is not None: + outstr += '"%s",' % str(item).replace('"','""') + else: + outstr += '"",' + else: + if item is not None: + outstr += '"%s"\n' % str(item).replace('"','""') + else: + outstr += '""\n' + outfile.write(outstr) + outfile.close() + + elif self.fmt == 'xml': + from lxml import etree + + from calibre.utils.genshi.template import MarkupTemplate + + PY_NAMESPACE = "http://genshi.edgewall.org/" + PY = "{%s}" % PY_NAMESPACE + NSMAP = {'py' : PY_NAMESPACE} + root = etree.Element('calibredb', nsmap=NSMAP) + py_for = etree.SubElement(root, PY + 'for', each="record in data") + record = etree.SubElement(py_for, 'record') + + if 'id' in fields: + record_child = etree.SubElement(record, 'id') + record_child.set(PY + "if", "record['id']") + record_child.text = "${record['id']}" + + if 'uuid' in fields: + record_child = etree.SubElement(record, 'uuid') + record_child.set(PY + "if", "record['uuid']") + record_child.text = "${record['uuid']}" + + if 'title' in fields: + record_child = etree.SubElement(record, 'title') + record_child.set(PY + "if", "record['title']") + record_child.text = "${record['title']}" + + if 'authors' in fields: + record_child = etree.SubElement(record, 'authors', sort="${record['author_sort']}") + record_subchild = etree.SubElement(record_child, PY + 'for', each="author in record['authors']") + record_subsubchild = etree.SubElement(record_subchild, 'author') + record_subsubchild.text = '$author' + + if 'publisher' in fields: + record_child = etree.SubElement(record, 'publisher') + record_child.set(PY + "if", "record['publisher']") + record_child.text = "${record['publisher']}" + + if 'rating' in fields: + record_child = etree.SubElement(record, 'rating') + record_child.set(PY + "if", "record['rating']") + record_child.text = "${record['rating']}" + + if 'date' in fields: + record_child = etree.SubElement(record, 'date') + record_child.set(PY + "if", "record['date']") + record_child.text = "${record['date']}" + + if 'pubdate' in fields: + record_child = etree.SubElement(record, 'pubdate') + record_child.set(PY + "if", "record['pubdate']") + record_child.text = "${record['pubdate']}" + + if 'size' in fields: + record_child = etree.SubElement(record, 'size') + record_child.set(PY + "if", "record['size']") + record_child.text = "${record['size']}" + + if 'tags' in fields: + # + # + # $tag + # + # + record_child = etree.SubElement(record, 'tags') + record_child.set(PY + "if", "record['tags']") + record_subchild = etree.SubElement(record_child, PY + 'for', each="tag in record['tags']") + record_subsubchild = etree.SubElement(record_subchild, 'tag') + record_subsubchild.text = '$tag' + + if 'comments' in fields: + record_child = etree.SubElement(record, 'comments') + record_child.set(PY + "if", "record['comments']") + record_child.text = "${record['comments']}" + + if 'series' in fields: + # + # ${record['series']} + # + record_child = etree.SubElement(record, 'series') + record_child.set(PY + "if", "record['series']") + record_child.set('index', "${record['series_index']}") + record_child.text = "${record['series']}" + + if 'isbn' in fields: + record_child = etree.SubElement(record, 'isbn') + record_child.set(PY + "if", "record['isbn']") + record_child.text = "${record['isbn']}" + + if 'cover' in fields: + # + # ${record['cover'].replace(os.sep, '/')} + # + record_child = etree.SubElement(record, 'cover') + record_child.set(PY + "if", "record['cover']") + record_child.text = "${record['cover']}" + + if 'formats' in fields: + # + # + # ${path.replace(os.sep, '/')} + # + # + record_child = etree.SubElement(record, 'formats') + record_child.set(PY + "if", "record['formats']") + record_subchild = etree.SubElement(record_child, PY + 'for', each="path in record['formats']") + record_subsubchild = etree.SubElement(record_subchild, 'format') + record_subsubchild.text = "${path.replace(os.sep, '/')}" + + outfile = open(path_to_output, 'w') + template = MarkupTemplate(etree.tostring(root, xml_declaration=True, + encoding="UTF-8", pretty_print=True)) + outfile.write(template.generate(data=data, os=os).render('xml')) + outfile.close() + + return None +