mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Files place modification for bibtex catalog export and various fixes
This commit is contained in:
parent
4fb3a73d85
commit
dbf741072e
@ -1,7 +1,7 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Greg Riker <griker at hotmail.com>'
|
__copyright__ = '2010, Greg Riker <griker at hotmail.com>'
|
||||||
|
|
||||||
import datetime, htmlentitydefs, os, re, shutil, codecs
|
import datetime, htmlentitydefs, os, re, shutil
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
@ -18,7 +18,7 @@ from calibre.utils.date import isoformat, now as nowf
|
|||||||
from calibre.utils.logging import default_log as log
|
from calibre.utils.logging import default_log as log
|
||||||
|
|
||||||
#Bibtex functions
|
#Bibtex functions
|
||||||
from calibre.library.bibtex import create_bibtex_entry, utf8ToBibtex
|
from calibre.utils.bibtex import bibtex_author_format, utf8ToBibtex, ValidateCitationKey
|
||||||
|
|
||||||
FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
||||||
'cover', 'formats', 'id', 'isbn', 'pubdate', 'publisher', 'rating',
|
'cover', 'formats', 'id', 'isbn', 'pubdate', 'publisher', 'rating',
|
||||||
@ -218,6 +218,101 @@ class BIBTEX(CatalogPlugin):
|
|||||||
"Applies to: BIBTEX output format"))]
|
"Applies to: BIBTEX output format"))]
|
||||||
|
|
||||||
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
def create_bibtex_entry(entry, fields, mode = "mixed"):
|
||||||
|
#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
|
||||||
|
|
||||||
|
bibtex_entry = []
|
||||||
|
if mode != "misc" and check_entry_book_valid(entry) :
|
||||||
|
bibtex_entry.append(u'@book{')
|
||||||
|
elif mode != "book" :
|
||||||
|
bibtex_entry.append(u'@misc{')
|
||||||
|
else :
|
||||||
|
#case strict book
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# Citation tag (not the best should be a user defined thing with regexp)
|
||||||
|
if not len(entry["isbn"]) == 0 :
|
||||||
|
bibtex_entry.append(u'%s' % utf8ToBibtex(ValidateCitationKey(re.sub(u'[\D]',
|
||||||
|
u'', entry["isbn"]))))
|
||||||
|
else :
|
||||||
|
bibtex_entry.append(u'%s' % utf8ToBibtex(ValidateCitationKey(str(entry["id"]))))
|
||||||
|
|
||||||
|
bibtex_entry = [u' '.join(bibtex_entry)]
|
||||||
|
|
||||||
|
for field in fields:
|
||||||
|
item = entry[field]
|
||||||
|
#check if the field should be included (none or empty)
|
||||||
|
if item is None:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if len(item) == 0 :
|
||||||
|
continue
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if field == 'authors' :
|
||||||
|
bibtex_entry.append(u'author = "%s"' % bibtex_author_format(item))
|
||||||
|
|
||||||
|
elif field in ['title', 'publisher', 'cover', 'uuid',
|
||||||
|
'author_sort', 'series'] :
|
||||||
|
bibtex_entry.append(u'%s = "%s"' % (field, utf8ToBibtex(item)))
|
||||||
|
|
||||||
|
elif field == 'id' :
|
||||||
|
bibtex_entry.append(u'calibreid = "%s"' % int(item))
|
||||||
|
|
||||||
|
elif field == 'rating' :
|
||||||
|
bibtex_entry.append(u'rating = "%s"' % int(item))
|
||||||
|
|
||||||
|
elif field == 'size' :
|
||||||
|
bibtex_entry.append(u'%s = "%s octets"' % (field, int(item)))
|
||||||
|
|
||||||
|
elif field == 'tags' :
|
||||||
|
#A list to flatten
|
||||||
|
bibtex_entry.append(u'tags = "%s"' % utf8ToBibtex(u', '.join(item)))
|
||||||
|
|
||||||
|
elif field == 'comments' :
|
||||||
|
#\n removal
|
||||||
|
bibtex_entry.append(u'note = "%s"' % utf8ToBibtex(item.replace(u'\n',u' ')))
|
||||||
|
|
||||||
|
elif field == 'isbn' :
|
||||||
|
# Could be 9, 10 or 13 digits
|
||||||
|
bibtex_entry.append(u'isbn = "%s"' % re.sub(u'[\D]', u'', item))
|
||||||
|
|
||||||
|
elif field == 'formats' :
|
||||||
|
item = u', '.join([format.rpartition('.')[2].lower() for format in item])
|
||||||
|
bibtex_entry.append(u'formats = "%s"' % item)
|
||||||
|
|
||||||
|
elif field == 'series_index' :
|
||||||
|
bibtex_entry.append(u'volume = "%s"' % int(item))
|
||||||
|
|
||||||
|
elif field == 'timestamp' :
|
||||||
|
bibtex_entry.append(u'timestamp = "%s"' % isoformat(item).partition('T')[0])
|
||||||
|
|
||||||
|
elif field == 'pubdate' :
|
||||||
|
bibtex_entry.append(u'year = "%s"' % item.year)
|
||||||
|
#Messing locale in date string formatting
|
||||||
|
bibtex_entry.append(u'month = "%s"' % utf8ToBibtex(item.strftime("%b").decode(preferred_encoding)))
|
||||||
|
#bibtex_entry.append('month = "%s"' % utf8ToBibtex(item.strftime("%B").decode(getlocale()[1])))
|
||||||
|
|
||||||
|
bibtex_entry = u',\n '.join(bibtex_entry)
|
||||||
|
bibtex_entry += u' }\n\n'
|
||||||
|
|
||||||
|
return bibtex_entry
|
||||||
|
|
||||||
|
def check_entry_book_valid(entry):
|
||||||
|
#Check that the required fields are ok for a book entry
|
||||||
|
for field in ['title', 'authors', 'publisher'] :
|
||||||
|
if entry[field] is None or len(entry[field]) == 0 :
|
||||||
|
return False
|
||||||
|
if entry['pubdate'] is None :
|
||||||
|
return False
|
||||||
|
else :
|
||||||
|
return True
|
||||||
|
|
||||||
self.fmt = path_to_output.rpartition('.')[2]
|
self.fmt = path_to_output.rpartition('.')[2]
|
||||||
self.notification = notification
|
self.notification = notification
|
||||||
|
|
||||||
@ -238,7 +333,6 @@ class BIBTEX(CatalogPlugin):
|
|||||||
else:
|
else:
|
||||||
log(" Fields: %s" % opts_dict['fields'])
|
log(" Fields: %s" % opts_dict['fields'])
|
||||||
|
|
||||||
|
|
||||||
# If a list of ids are provided, don't use search_text
|
# If a list of ids are provided, don't use search_text
|
||||||
if opts.ids:
|
if opts.ids:
|
||||||
opts.search_text = None
|
opts.search_text = None
|
||||||
@ -255,15 +349,16 @@ class BIBTEX(CatalogPlugin):
|
|||||||
log.error("\nNo matching database entries for search criteria '%s'" % opts.search_text)
|
log.error("\nNo matching database entries for search criteria '%s'" % opts.search_text)
|
||||||
|
|
||||||
#Open output and write entries
|
#Open output and write entries
|
||||||
outfile = codecs.open(path_to_output, 'w', 'ascii')
|
#replace should be an option and not the default to generate errors for improving
|
||||||
|
outfile = codecs.open(path_to_output, 'w', 'ascii','replace')
|
||||||
|
|
||||||
#File header
|
#File header
|
||||||
nb_entries = len(vars(opts)['ids'])
|
nb_entries = len(opts.ids)
|
||||||
outfile.write(u'%%%Calibre catalog\n%%%{0} entries in catalog\n\n'.format(nb_entries))
|
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'
|
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)))
|
% (nb_entries, nowf().strftime("%A, %d. %B %Y %H:%M").decode(preferred_encoding)))
|
||||||
|
|
||||||
#Entries
|
#Entries wrintng after Bibtex formating
|
||||||
for entry in data:
|
for entry in data:
|
||||||
outfile.write(create_bibtex_entry(entry, fields))
|
outfile.write(create_bibtex_entry(entry, fields))
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
""" Collection of python utility-methodes commonly used by other
|
""" Collection of python utility-methodes commonly used by other
|
||||||
bibliograph packages.
|
bibliograph packages.
|
||||||
From http://pypi.python.org/pypi/bibliograph.core/
|
From http://pypi.python.org/pypi/bibliograph.core/
|
||||||
|
from Tom Gross <itconsense@gmail.com>
|
||||||
|
|
||||||
|
Adapted for calibre use
|
||||||
|
|
||||||
Zope Public License (ZPL) Version 2.1
|
Zope Public License (ZPL) Version 2.1
|
||||||
|
|
||||||
@ -60,15 +63,10 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__docformat__ = 'reStructuredText'
|
__docformat__ = 'reStructuredText'
|
||||||
__author__ = 'Tom Gross <itconsense@gmail.com>'
|
__author__ = 'sengian <sengian1 at gmail.com>'
|
||||||
|
|
||||||
import os, re, string
|
import os, re, string
|
||||||
|
|
||||||
#from locale import getlocale
|
|
||||||
from calibre.constants import preferred_encoding
|
|
||||||
from calibre import strftime
|
|
||||||
from calibre.utils.date import isoformat
|
|
||||||
|
|
||||||
utf8enc2latex_mapping = {
|
utf8enc2latex_mapping = {
|
||||||
# This is a mapping of Unicode characters to LaTeX equivalents.
|
# This is a mapping of Unicode characters to LaTeX equivalents.
|
||||||
# The information has been extracted from
|
# The information has been extracted from
|
||||||
@ -77,6 +75,37 @@ utf8enc2latex_mapping = {
|
|||||||
#
|
#
|
||||||
# The extraction has been done by the "create_unimap.py" script
|
# The extraction has been done by the "create_unimap.py" script
|
||||||
# located at <http://docutils.sf.net/tools/dev/create_unimap.py>.
|
# located at <http://docutils.sf.net/tools/dev/create_unimap.py>.
|
||||||
|
|
||||||
|
#Fix some encoding problem between cp1252 and latin1
|
||||||
|
# from http://www.microsoft.com/typography/unicode/1252.htm
|
||||||
|
u'\x80': '{\\mbox{\\texteuro}}', # EURO SIGN
|
||||||
|
u'\x82': '{,}', # SINGLE LOW-9 QUOTATION MARK
|
||||||
|
u'\x83': '$f$', # LATIN SMALL LETTER F WITH HOOK
|
||||||
|
u'\x84': '{,,}', # DOUBLE LOW-9 QUOTATION MARK
|
||||||
|
u'\x85': '{\\ldots}', # HORIZONTAL ELLIPSIS
|
||||||
|
u'\x86': '{\\textdagger}', # DAGGER
|
||||||
|
u'\x87': '{\\textdaggerdbl}', # DOUBLE DAGGER
|
||||||
|
u'\x88': '{\textasciicircum}', # MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||||
|
u'\x89': '{\\textperthousand}', # PER MILLE SIGN
|
||||||
|
u'\x8A': '{\\v{S}}', # LATIN CAPITAL LETTER S WITH CARON
|
||||||
|
u'\x8B': '{\\guilsinglleft}', # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||||
|
u'\x8C': '{\\OE}', # LATIN CAPITAL LIGATURE OE
|
||||||
|
u'\x8E': '{\\v{Z}}', # LATIN CAPITAL LETTER Z WITH CARON
|
||||||
|
u'\x91': '{`}', # LEFT SINGLE QUOTATION MARK
|
||||||
|
u'\x92': "{'}", # RIGHT SINGLE QUOTATION MARK
|
||||||
|
u'\x93': '{\\textquotedblleft}', # LEFT DOUBLE QUOTATION MARK
|
||||||
|
u'\x94': '{\\textquotedblright}', # RIGHT DOUBLE QUOTATION MARK
|
||||||
|
u'\x95': '{\\textbullet}', # BULLET
|
||||||
|
u'\x96': '{\\textendash}', # EN DASH
|
||||||
|
u'\x97': '{\\textemdash}', # EM DASH
|
||||||
|
u'\x98': '{\\texttildelow}', # SMALL TILDE
|
||||||
|
u'\x99': '{\\texttrademark}', # TRADE MARK SIGN
|
||||||
|
u'\x9A': '{\\v{s}}', # LATIN SMALL LETTER S WITH CARON
|
||||||
|
u'\x9B': '{\\guilsinglright}', # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||||
|
u'\x9C': '{\\oe}', # LATIN SMALL LIGATURE OE
|
||||||
|
u'\x9E': '{\\v{z}}', # LATIN SMALL LETTER Z WITH CARON
|
||||||
|
u'\x9F': '{\\"{Y}}', # LATIN CAPITAL LETTER Y WITH DIAERESIS
|
||||||
|
|
||||||
u'\xa0': '$~$',
|
u'\xa0': '$~$',
|
||||||
u'\xa1': '{\\textexclamdown}',
|
u'\xa1': '{\\textexclamdown}',
|
||||||
u'\xa2': '{\\textcent}',
|
u'\xa2': '{\\textcent}',
|
||||||
@ -2494,100 +2523,22 @@ def escapeSpecialCharacters(text):
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
#Calibre functions
|
#Calibre functions
|
||||||
#Go from an unicode entry to ASCII Bibtex format without encoding (try to decode if needed)
|
#Go from an unicode entry to ASCII Bibtex format without encoding
|
||||||
def utf8ToBibtex(text):
|
def utf8ToBibtex(text, asccii_bibtex = True):
|
||||||
if len(text) == 0:
|
if len(text) == 0:
|
||||||
return ''
|
return ''
|
||||||
try :
|
'''try :
|
||||||
text = text.decode(preferred_encoding)
|
text = text.decode('cp1252')
|
||||||
except (TypeError, UnicodeDecodeError, ValueError):
|
except (TypeError, UnicodeDecodeError, ValueError):
|
||||||
pass
|
pass '''
|
||||||
text.replace('\\', '\\\\')
|
text.replace('\\', '\\\\')
|
||||||
text = resolveEntities(text)
|
text = resolveEntities(text)
|
||||||
|
if asccii_bibtex :
|
||||||
text = resolveUnicode(text)
|
text = resolveUnicode(text)
|
||||||
text = escapeSpecialCharacters(text)
|
return escapeSpecialCharacters(text)
|
||||||
return text
|
|
||||||
|
|
||||||
def create_bibtex_entry(entry, fields, mode = "mixed"):
|
|
||||||
#Bibtex doesn't like UTF-8 but keep unicode until writing
|
|
||||||
#Define starting chain as a misc then overide if book valid
|
|
||||||
bibtex_entry = []
|
|
||||||
if mode != "misc" and check_entry_book_valid(entry) :
|
|
||||||
bibtex_entry.append(u'@book{')
|
|
||||||
else :
|
|
||||||
bibtex_entry.append(u'@misc{')
|
|
||||||
|
|
||||||
# Citation tag (not the best should be a user defined thing with regexp)
|
|
||||||
if not len(entry["isbn"]) == 0 :
|
|
||||||
bibtex_entry.append(u'%s' % utf8ToBibtex(ValidateCitationKey(re.sub(u'[\D]',
|
|
||||||
u'', entry["isbn"]))))
|
|
||||||
else :
|
|
||||||
bibtex_entry.append(u'%s' % utf8ToBibtex(ValidateCitationKey(str(entry["id"]))))
|
|
||||||
|
|
||||||
bibtex_entry = [u' '.join(bibtex_entry)]
|
|
||||||
|
|
||||||
for field in fields:
|
|
||||||
item = entry[field]
|
|
||||||
#check if the field should be included (none or empty)
|
|
||||||
if item is None:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
if len(item) == 0 :
|
|
||||||
continue
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if field == 'authors' :
|
|
||||||
bibtex_entry.append(u'author = "%s"' % bibtex_author_format(item))
|
|
||||||
elif field in ['title', 'publisher', 'cover', 'uuid',
|
|
||||||
'author_sort', 'series'] :
|
|
||||||
bibtex_entry.append(u'%s = "%s"' % (field, utf8ToBibtex(item)))
|
|
||||||
elif field == 'id' :
|
|
||||||
bibtex_entry.append(u'calibreid = "%s"' % int(item))
|
|
||||||
elif field == 'rating' :
|
|
||||||
bibtex_entry.append(u'rating = "%s"' % int(item))
|
|
||||||
elif field == 'size' :
|
|
||||||
bibtex_entry.append(u'%s = "%s octets"' % (field, int(item)))
|
|
||||||
elif field == 'tags' :
|
|
||||||
#A list to flatten
|
|
||||||
bibtex_entry.append(u'tags = "%s"' % utf8ToBibtex(u', '.join(item)))
|
|
||||||
elif field == 'comments' :
|
|
||||||
#\n removal
|
|
||||||
bibtex_entry.append(u'note = "%s"' % utf8ToBibtex(item.replace(u'\n',u' ')))
|
|
||||||
elif field == 'isbn' :
|
|
||||||
# Could be 9, 10 or 13 digits
|
|
||||||
bibtex_entry.append(u'isbn = "%s"' % re.sub(u'[\D]', u'', item))
|
|
||||||
elif field == 'formats' :
|
|
||||||
item = u', '.join([format.rpartition('.')[2].lower() for format in item])
|
|
||||||
bibtex_entry.append(u'formats = "%s"' % item)
|
|
||||||
elif field == 'series_index' :
|
|
||||||
bibtex_entry.append(u'volume = "%s"' % int(item))
|
|
||||||
elif field == 'timestamp' :
|
|
||||||
bibtex_entry.append(u'timestamp = "%s"' % isoformat(item).partition('T')[0])
|
|
||||||
elif field == 'pubdate' :
|
|
||||||
bibtex_entry.append(u'year = "%s"' % item.year)
|
|
||||||
#Messing locale in date string formatting
|
|
||||||
bibtex_entry.append(u'month = "%s"' % utf8ToBibtex(item.strftime("%b")))
|
|
||||||
#bibtex_entry.append('month = "%s"' % utf8ToBibtex(item.strftime("%B").decode(getlocale()[1])))
|
|
||||||
|
|
||||||
bibtex_entry = u',\n '.join(bibtex_entry)
|
|
||||||
bibtex_entry += u' }\n\n'
|
|
||||||
|
|
||||||
return bibtex_entry
|
|
||||||
|
|
||||||
def check_entry_book_valid(entry):
|
|
||||||
#Check that the required fields are ok for a book entry
|
|
||||||
for field in ['title', 'authors', 'publisher'] :
|
|
||||||
if entry[field] is None or len(entry[field]) == 0 :
|
|
||||||
return False
|
|
||||||
if entry['pubdate'] is None :
|
|
||||||
return False
|
|
||||||
else :
|
|
||||||
return True
|
|
||||||
|
|
||||||
def bibtex_author_format(item):
|
def bibtex_author_format(item):
|
||||||
#Format authors for Bibtex compliance
|
#Format authors for Bibtex compliance (get a list as input)
|
||||||
item = u' and'.join([author for author in item])
|
item = u' and'.join([author for author in item])
|
||||||
return utf8ToBibtex(item)
|
return utf8ToBibtex(item)
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user