diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py index 92ee2ca6d2..15bd54c80c 100644 --- a/src/calibre/__init__.py +++ b/src/calibre/__init__.py @@ -361,6 +361,8 @@ def strftime(fmt, t=None): before 1900 ''' if t is None: t = time.localtime() + if hasattr(t, 'timetuple'): + t = t.timetuple() early_year = t[0] < 1900 if early_year: replacement = 1900 if t[0]%4 == 0 else 1901 diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 65627f56ca..35cb0ad3d2 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -446,7 +446,7 @@ from calibre.devices.eb600.driver import EB600, COOL_ER, SHINEBOOK, \ BOOQ, ELONEX, POCKETBOOK301, MENTOR from calibre.devices.iliad.driver import ILIAD from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800 -from calibre.devices.jetbook.driver import JETBOOK +from calibre.devices.jetbook.driver import JETBOOK, MIBUK from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX from calibre.devices.nook.driver import NOOK from calibre.devices.prs505.driver import PRS505 @@ -517,6 +517,7 @@ plugins += [ IREXDR1000, IREXDR800, JETBOOK, + MIBUK, SHINEBOOK, POCKETBOOK360, POCKETBOOK301, diff --git a/src/calibre/devices/jetbook/driver.py b/src/calibre/devices/jetbook/driver.py index 671fea5d75..6a3bc635ff 100644 --- a/src/calibre/devices/jetbook/driver.py +++ b/src/calibre/devices/jetbook/driver.py @@ -80,3 +80,21 @@ class JETBOOK(USBMS): return mi +class MIBUK(USBMS): + + name = 'MiBuk Wolder Device Interface' + description = _('Communicate with the MiBuk Wolder reader.') + author = 'Kovid Goyal' + supported_platforms = ['windows', 'osx', 'linux'] + + FORMATS = ['epub', 'mobi', 'prc', 'fb2', 'txt', 'rtf', 'pdf'] + + VENDOR_ID = [0x0525] + PRODUCT_ID = [0xa4a5] + BCD = [0x314] + SUPPORTS_SUB_DIRS = True + + VENDOR_NAME = 'LINUX' + WINDOWS_MAIN_MEM = 'WOLDERMIBUK' + + diff --git a/src/calibre/gui2/convert/metadata.ui b/src/calibre/gui2/convert/metadata.ui index ec5a913f18..7bc45e234e 100644 --- a/src/calibre/gui2/convert/metadata.ui +++ b/src/calibre/gui2/convert/metadata.ui @@ -20,6 +20,30 @@ Book Cover + + + + + + + 0 + 0 + + + + + + + + + + Use cover from &source file + + + true + + + @@ -71,30 +95,6 @@ - - - - Use cover from &source file - - - true - - - - - - - - - - 0 - 0 - - - - - - opt_prefer_metadata_cover @@ -232,9 +232,6 @@ QComboBox::InsertAlphabetically - - QComboBox::AdjustToContents - diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui index 4efb48d870..5da9d37d04 100644 --- a/src/calibre/gui2/dialogs/metadata_single.ui +++ b/src/calibre/gui2/dialogs/metadata_single.ui @@ -277,12 +277,6 @@ - - - 0 - 0 - - List of known series. You can add new series. @@ -295,9 +289,6 @@ QComboBox::InsertAlphabetically - - QComboBox::AdjustToContents - diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 97758482fc..994fa4575f 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -490,6 +490,7 @@ class EnComboBox(QComboBox): QComboBox.__init__(self, *args) self.setLineEdit(EnLineEdit(self)) self.setAutoCompletionCaseSensitivity(Qt.CaseSensitive) + self.setMinimumContentsLength(20) def text(self): return unicode(self.currentText()) diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index 04b85687c5..697396304f 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -28,6 +28,10 @@ FIELDS = ['all', 'author_sort', 'authors', 'comments', TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', 'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ] +#Allowed fields for template +TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', + 'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ] + class CSV_XML(CatalogPlugin): 'CSV/XML catalog generator' @@ -126,7 +130,11 @@ class CSV_XML(CatalogPlugin): item = item.replace(u'\n',u' ') outstr.append(u'"%s"' % unicode(item).replace('"','""')) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE outfile.write(u','.join(outstr) + u'\n') outfile.close() @@ -208,7 +216,11 @@ class BIBTEX(CatalogPlugin): 'Available fields: %s.\n' "Default: '%%default'\n" "Applies to: BIBTEX output format")%', '.join(FIELDS)), +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE Option('--sort-by', default = 'id', dest = 'sort_by', @@ -217,7 +229,11 @@ class BIBTEX(CatalogPlugin): 'Available fields: author_sort, id, rating, size, timestamp, title.\n' "Default: '%default'\n" "Applies to: BIBTEX output format")), +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE Option('--create-citation', default = 'True', dest = 'impcit', @@ -226,7 +242,11 @@ class BIBTEX(CatalogPlugin): 'Boolean value: True, False\n' "Default: '%default'\n" "Applies to: BIBTEX output format")), +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE Option('--citation-template', default = '{authors}{id}', dest = 'bib_cit', @@ -236,7 +256,11 @@ class BIBTEX(CatalogPlugin): 'Available fields: %s.\n' "Default: '%%default'\n" "Applies to: BIBTEX output format")%', '.join(TEMPLATE_ALLOWED_FIELDS)), +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE Option('--choose-encoding', default = 'utf8', dest = 'bibfile_enc', @@ -245,7 +269,11 @@ class BIBTEX(CatalogPlugin): 'Available types: utf8, cp1252, ascii.\n' "Default: '%default'\n" "Applies to: BIBTEX output format")), +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE Option('--choose-encoding-configuration', default = 'strict', dest = 'bibfile_enctag', @@ -263,21 +291,46 @@ class BIBTEX(CatalogPlugin): 'Available types: book, misc, mixed.\n' "Default: '%default'\n" "Applies to: BIBTEX output format"))] +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE def run(self, path_to_output, opts, db, notification=DummyReporter()): +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE from types import StringType, UnicodeType +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE from calibre.library.save_to_disk import preprocess_template #Bibtex functions from calibre.utils.bibtex import bibtex_author_format, utf8ToBibtex, ValidateCitationKey +<<<<<<< TREE def create_bibtex_entry(entry, fields, mode, template_citation, +======= + + def create_bibtex_entry(entry, fields, mode, template_citation, +>>>>>>> MERGE-SOURCE asccii_bibtex = True, citation_bibtex = True): +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #Bibtex doesn't like UTF-8 but keep unicode until writing #Define starting chain or if book valid strict and not book return a Fail string +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE bibtex_entry = [] if mode != "misc" and check_entry_book_valid(entry) : bibtex_entry.append(u'@book{') @@ -286,12 +339,20 @@ class BIBTEX(CatalogPlugin): else : #case strict book return '' +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE if citation_bibtex : # Citation tag bibtex_entry.append(make_bibtex_citation(entry, template_citation, asccii_bibtex)) bibtex_entry = [u' '.join(bibtex_entry)] +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE for field in fields: item = entry[field] #check if the field should be included (none or empty) @@ -305,55 +366,117 @@ class BIBTEX(CatalogPlugin): if field == 'authors' : bibtex_entry.append(u'author = "%s"' % bibtex_author_format(item)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field in ['title', 'publisher', 'cover', 'uuid', 'author_sort', 'series'] : bibtex_entry.append(u'%s = "%s"' % (field, utf8ToBibtex(item, asccii_bibtex))) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'id' : bibtex_entry.append(u'calibreid = "%s"' % int(item)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'rating' : bibtex_entry.append(u'rating = "%s"' % int(item)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'size' : bibtex_entry.append(u'%s = "%s octets"' % (field, int(item))) +<<<<<<< TREE elif field == 'tags' : +======= + + elif field == 'tags' : +>>>>>>> MERGE-SOURCE #A list to flatten bibtex_entry.append(u'tags = "%s"' % utf8ToBibtex(u', '.join(item), asccii_bibtex)) +<<<<<<< TREE elif field == 'comments' : +======= + + elif field == 'comments' : +>>>>>>> MERGE-SOURCE #\n removal item = item.replace(u'\r\n',u' ') item = item.replace(u'\n',u' ') bibtex_entry.append(u'note = "%s"' % utf8ToBibtex(item, asccii_bibtex)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'isbn' : # Could be 9, 10 or 13 digits bibtex_entry.append(u'isbn = "%s"' % re.sub(u'[\D]', u'', item)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'formats' : item = u', '.join([format.rpartition('.')[2].lower() for format in item]) bibtex_entry.append(u'formats = "%s"' % item) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'series_index' : bibtex_entry.append(u'volume = "%s"' % int(item)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'timestamp' : bibtex_entry.append(u'timestamp = "%s"' % isoformat(item).partition('T')[0]) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE elif field == 'pubdate' : bibtex_entry.append(u'year = "%s"' % item.year) +<<<<<<< TREE #Messing locale in date string formatting bibtex_entry.append(u'month = "%s"' % utf8ToBibtex(item.strftime("%b").decode(preferred_encoding), +======= + bibtex_entry.append(u'month = "%s"' % utf8ToBibtex(strftime("%b", item), +>>>>>>> MERGE-SOURCE asccii_bibtex)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE bibtex_entry = u',\n '.join(bibtex_entry) bibtex_entry += u' }\n\n' +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE return bibtex_entry +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE def check_entry_book_valid(entry): #Check that the required fields are ok for a book entry for field in ['title', 'authors', 'publisher'] : @@ -365,12 +488,24 @@ class BIBTEX(CatalogPlugin): return True def make_bibtex_citation(entry, template_citation, asccii_bibtex): +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #define a function to replace the template entry by its value def tpl_replace(objtplname) : +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE tpl_field = re.sub(u'[\{\}]', u'', objtplname.group()) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE if tpl_field in TEMPLATE_ALLOWED_FIELDS : if tpl_field in ['pubdate', 'timestamp'] : tpl_field = isoformat(entry[tpl_field]).partition('T')[0] @@ -382,34 +517,66 @@ class BIBTEX(CatalogPlugin): tpl_field = entry[tpl_field] return tpl_field else: +<<<<<<< TREE return u'' +======= + return u'' +>>>>>>> MERGE-SOURCE if len(template_citation) >0 : +<<<<<<< TREE tpl_citation = utf8ToBibtex(ValidateCitationKey(re.sub(u'\{[^{}]*\}', +======= + tpl_citation = utf8ToBibtex(ValidateCitationKey(re.sub(u'\{[^{}]*\}', +>>>>>>> MERGE-SOURCE tpl_replace, template_citation)), asccii_bibtex) if len(tpl_citation) >0 : return tpl_citation +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE if len(entry["isbn"]) > 0 : template_citation = u'%s' % re.sub(u'[\D]',u'', entry["isbn"]) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE else : template_citation = u'%s' % str(entry["id"]) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE if asccii_bibtex : return ValidateCitationKey(template_citation.encode('ascii', 'replace')) else : return ValidateCitationKey(template_citation) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE self.fmt = path_to_output.rpartition('.')[2] self.notification = notification +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE # Combobox options bibfile_enc = ['utf8', 'cp1252', 'ascii'] bibfile_enctag = ['strict', 'replace', 'ignore', 'backslashreplace'] bib_entry = ['mixed', 'misc', 'book'] +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE # Needed beacause CLI return str vs int by widget try: bibfile_enc = bibfile_enc[opts.bibfile_enc] @@ -448,9 +615,17 @@ class BIBTEX(CatalogPlugin): log(" Fields: %s" % ', '.join(FIELDS[1:])) else: log(" Fields: %s" % opts_dict['fields']) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE log(" Output file will be encoded in %s with %s flag" % (bibfile_enc, bibfile_enctag)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE log(" BibTeX entry type is %s with a citation like '%s' flag" % (bib_entry, opts_dict['bib_cit'])) # If a list of ids are provided, don't use search_text @@ -464,16 +639,28 @@ class BIBTEX(CatalogPlugin): # Get the requested output fields as a list fields = self.get_output_fields(opts) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE if not len(data): log.error("\nNo matching database entries for search criteria '%s'" % opts.search_text) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #Entries writing after Bibtex formating (or not) if bibfile_enc != 'ascii' : asccii_bibtex = False else : asccii_bibtex = True +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #Check and go to default in case of bad CLI if isinstance(opts.impcit, (StringType, UnicodeType)) : if opts.impcit == 'False' : @@ -485,30 +672,62 @@ class BIBTEX(CatalogPlugin): citation_bibtex= True else : citation_bibtex= opts.impcit +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE template_citation = preprocess_template(opts.bib_cit) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #Open output and write entries outfile = codecs.open(path_to_output, 'w', bibfile_enc, bibfile_enctag) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #File header nb_entries = len(data) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE #check in book strict if all is ok else throw a warning into log if bib_entry == 'book' : nb_books = len(filter(check_entry_book_valid, data)) if nb_books < nb_entries : log(" WARNING: only %d entries in %d are book compatible" % (nb_books, nb_entries)) nb_entries = nb_books +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE outfile.write(u'%%%Calibre catalog\n%%%{0} entries in catalog\n\n'.format(nb_entries)) outfile.write(u'@preamble{"This catalog of %d entries was generated by calibre on %s"}\n\n' % (nb_entries, nowf().strftime("%A, %d. %B %Y %H:%M").decode(preferred_encoding))) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE for entry in data: +<<<<<<< TREE outfile.write(create_bibtex_entry(entry, fields, bib_entry, template_citation, +======= + outfile.write(create_bibtex_entry(entry, fields, bib_entry, template_citation, +>>>>>>> MERGE-SOURCE asccii_bibtex, citation_bibtex)) +<<<<<<< TREE +======= + +>>>>>>> MERGE-SOURCE outfile.close() class EPUB_MOBI(CatalogPlugin): diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index e039f5a817..5b459c6d2a 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -12,6 +12,7 @@ from math import floor from calibre import prints from calibre.constants import preferred_encoding +from calibre.library.field_metadata import FieldMetadata from calibre.utils.date import parse_date class CustomColumns(object): @@ -30,6 +31,10 @@ class CustomColumns(object): def __init__(self): + # Verify that CUSTOM_DATA_TYPES is a (possibly improper) subset of + # VALID_DATA_TYPES + if len(self.CUSTOM_DATA_TYPES - FieldMetadata.VALID_DATA_TYPES) > 0: + raise ValueError('Unknown custom column type in set') # Delete marked custom columns for record in self.conn.get( 'SELECT id FROM custom_columns WHERE mark_for_delete=1'): diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index 626683fee5..f29b432eec 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -30,8 +30,8 @@ class FieldMetadata(dict): label: the actual column label. No prefixing. - datatype: the type of the information in the field. Valid values are float, - int, rating, bool, comments, datetime, text. + datatype: the type of information in the field. Valid values are listed in + VALID_DATA_TYPES below. is_multiple: valid for the text datatype. If None, the field is to be treated as a single term. If not None, it contains a string, and the field is assumed to contain a list of terms separated by that string @@ -65,6 +65,10 @@ class FieldMetadata(dict): rec_index: the index of the field in the db metadata record. ''' + + VALID_DATA_TYPES = frozenset([None, 'rating', 'text', 'comments', 'datetime', + 'int', 'float', 'bool', 'series']) + _field_metadata = [ ('authors', {'table':'authors', 'column':'name', @@ -296,6 +300,8 @@ class FieldMetadata(dict): self._search_term_map = {} self.custom_label_to_key_map = {} for k,v in self._field_metadata: + if v['kind'] == 'field' and v['datatype'] not in self.VALID_DATA_TYPES: + raise ValueError('Unknown datatype %s for field %s'%(v['datatype'], k)) self._tb_cats[k] = v self._tb_cats[k]['label'] = k self._tb_cats[k]['display'] = {} @@ -377,6 +383,8 @@ class FieldMetadata(dict): key = self.custom_field_prefix + label if key in self._tb_cats: raise ValueError('Duplicate custom field [%s]'%(label)) + if datatype not in self.VALID_DATA_TYPES: + raise ValueError('Unknown datatype %s for field %s'%(datatype, key)) self._tb_cats[key] = {'table':table, 'column':column, 'datatype':datatype, 'is_multiple':is_multiple, 'kind':'field', 'name':name,