TXT Input: Add support for embedded images that use relative URLs when converting markdown or textile. Note that this will only work if you are converting using the ebook-convert command line tool as the main calibre program moves files around, so relative references will not be valid.

This commit is contained in:
Kovid Goyal 2018-04-30 11:53:48 +05:30
parent 49c048a028
commit bff950e52d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -67,10 +67,40 @@ class TXTInput(InputFormatPlugin):
help=_('Enable extensions to markdown syntax. Extensions are formatting that is not part '
'of the standard markdown format. The extensions enabled by default: %default.\n'
'To learn more about markdown extensions, see https://pythonhosted.org/Markdown/extensions/index.html\n'
'This should be a comma separated list of extensions to enable:\n') +
'\n'.join('* %s: %s' % (k, MD_EXTENSIONS[k]) for k in sorted(MD_EXTENSIONS))),
'This should be a comma separated list of extensions to enable:\n'
) + '\n'.join('* %s: %s' % (k, MD_EXTENSIONS[k]) for k in sorted(MD_EXTENSIONS))),
])
def shift_file(self, base_dir, fname, data):
name, ext = os.path.splitext(fname)
c = 1
while os.path.exists(os.path.join(base_dir, '{}-{}{}'.format(name, c, ext))):
c += 1
ans = os.path.join(base_dir, '{}-{}{}'.format(name, c, ext))
with open(ans, 'wb') as f:
f.write(data)
return f.name
def fix_resources(self, html, base_dir):
from html5_parser import parse
root = parse(html)
changed = False
for img in root.xpath('//img[@src]'):
src = img.get('src')
prefix = src.split(':', 1)[0].lower()
if prefix not in ('file', 'http', 'https', 'ftp') and not os.path.isabs(src):
src = os.path.join(base_dir, src)
if os.access(src, os.R_OK):
with open(src, 'rb') as f:
data = f.read()
f = self.shift_file(base_dir, os.path.basename(src), data)
changed = True
img.set('src', os.path.basename(f))
if changed:
from lxml import etree
html = etree.tostring(root, encoding='unicode')
return html
def convert(self, stream, options, file_ext, log,
accelerators):
from calibre.ebooks.conversion.preprocess import DocAnalysis, Dehyphenator
@ -87,6 +117,7 @@ class TXTInput(InputFormatPlugin):
txt = ''
log.debug('Reading text from file...')
length = 0
base_dir = os.getcwdu()
# Extract content from zip archive.
if file_ext == 'txtz':
@ -98,6 +129,8 @@ class TXTInput(InputFormatPlugin):
with open(x, 'rb') as tf:
txt += tf.read() + '\n\n'
else:
if getattr(stream, 'name', None):
base_dir = os.path.dirname(stream.name)
txt = stream.read()
if file_ext in {'md', 'textile', 'markdown'}:
options.formatting_type = {'md': 'markdown'}.get(file_ext, file_ext)
@ -194,6 +227,8 @@ class TXTInput(InputFormatPlugin):
txt = preserve_spaces(txt)
# Process the text using the appropriate text processor.
self.shifted_files = []
try:
html = ''
input_mi = None
if options.formatting_type == 'markdown':
@ -203,9 +238,11 @@ class TXTInput(InputFormatPlugin):
except RuntimeError:
raise ValueError('This txt file has malformed markup, it cannot be'
' converted by calibre. See https://daringfireball.net/projects/markdown/syntax')
html = self.fix_resources(html, base_dir)
elif options.formatting_type == 'textile':
log.debug('Running text through textile conversion...')
html = convert_textile(txt)
html = self.fix_resources(html, base_dir)
else:
log.debug('Running text through basic conversion...')
flow_size = getattr(options, 'flow_size', 0)
@ -217,24 +254,15 @@ class TXTInput(InputFormatPlugin):
for opt in html_input.options:
setattr(options, opt.option.name, opt.recommended_value)
options.input_encoding = 'utf-8'
base = os.getcwdu()
if file_ext != 'txtz' and hasattr(stream, 'name'):
base = os.path.dirname(stream.name)
fname = os.path.join(base, 'index.html')
c = 0
while os.path.exists(fname):
c += 1
fname = 'index%d.html'%c
htmlfile = open(fname, 'wb')
with htmlfile:
htmlfile.write(html.encode('utf-8'))
htmlfile = self.shift_file(base_dir, 'index.html', html.encode('utf-8'))
odi = options.debug_pipeline
options.debug_pipeline = None
# Generate oeb from html conversion.
oeb = html_input.convert(open(htmlfile.name, 'rb'), options, 'html', log,
{})
oeb = html_input.convert(open(htmlfile, 'rb'), options, 'html', log, {})
options.debug_pipeline = odi
os.remove(htmlfile.name)
finally:
for x in self.shifted_files:
os.remove(x)
# Set metadata from file.
if input_mi is None: