mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Start work on in-browser viewer
This commit is contained in:
parent
0cc6c5d901
commit
97734c5039
@ -91,6 +91,13 @@ class TOC(object):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return b'\n'.join([x.encode('utf-8') for x in self.get_lines()])
|
return b'\n'.join([x.encode('utf-8') for x in self.get_lines()])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_dict(self):
|
||||||
|
return {
|
||||||
|
'title':self.title, 'dest':self.dest, 'frag':self.frag, 'dest_exists':self.dest_exists, 'dest_error':self.dest_error,
|
||||||
|
'children':[c.as_dict for c in self.children]
|
||||||
|
}
|
||||||
|
|
||||||
def child_xpath(tag, name):
|
def child_xpath(tag, name):
|
||||||
return tag.xpath('./*[calibre:lower-case(local-name()) = "%s"]'%name)
|
return tag.xpath('./*[calibre:lower-case(local-name()) = "%s"]'%name)
|
||||||
|
|
||||||
|
137
src/calibre/srv/render_book.py
Normal file
137
src/calibre/srv/render_book.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
import sys, re, os, json
|
||||||
|
from functools import partial
|
||||||
|
from future_builtins import map
|
||||||
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
from cssutils import replaceUrls
|
||||||
|
from lxml.etree import Comment, tostring
|
||||||
|
|
||||||
|
from calibre.ebooks.oeb.base import OEB_DOCS, escape_cdata, OEB_STYLES, rewrite_links, XPath, urlunquote, XLINK
|
||||||
|
from calibre.ebooks.oeb.iterator.book import extract_book
|
||||||
|
from calibre.ebooks.oeb.polish.container import Container as ContainerBase
|
||||||
|
from calibre.ebooks.oeb.polish.toc import get_toc
|
||||||
|
from calibre.ebooks.oeb.polish.utils import guess_type
|
||||||
|
from calibre.utils.short_uuid import uuid4
|
||||||
|
from calibre.utils.logging import default_log
|
||||||
|
|
||||||
|
|
||||||
|
def encode_component(x):
|
||||||
|
return x.replace(',', ',c').replace('|', ',p')
|
||||||
|
|
||||||
|
def decode_component(x):
|
||||||
|
return x.replace(',p', '|').replace(',c', ',')
|
||||||
|
|
||||||
|
def encode_url(name, frag=''):
|
||||||
|
name = encode_component(name)
|
||||||
|
if frag:
|
||||||
|
name += ',,' + encode_component(frag)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def decode_url(x):
|
||||||
|
parts = list(map(decode_component, re.split(',,', x, 1)))
|
||||||
|
if len(parts) == 1:
|
||||||
|
parts.append('')
|
||||||
|
return parts
|
||||||
|
|
||||||
|
class Container(ContainerBase):
|
||||||
|
|
||||||
|
RENDER_VERSION = 1
|
||||||
|
tweak_mode = True
|
||||||
|
|
||||||
|
def __init__(self, path_to_ebook, tdir, log=None):
|
||||||
|
log = log or default_log
|
||||||
|
book_fmt, opfpath, input_fmt = extract_book(path_to_ebook, tdir, log=log)
|
||||||
|
ContainerBase.__init__(self, tdir, opfpath, log)
|
||||||
|
excluded_names = {
|
||||||
|
name for name, mt in self.mime_map.iteritems() if
|
||||||
|
name == self.opf_name or mt == guess_type('a.ncx') or name.startswith('META-INF/')
|
||||||
|
}
|
||||||
|
self.book_render_data = data = {
|
||||||
|
'version': self.RENDER_VERSION,
|
||||||
|
'toc':get_toc(self).as_dict,
|
||||||
|
'spine':[name for name, is_linear in self.spine_names],
|
||||||
|
'link_uid': uuid4(),
|
||||||
|
'is_comic': input_fmt.lower() in {'cbc', 'cbz', 'cbr', 'cb7'},
|
||||||
|
'manifest': list(set(self.name_path_map) - excluded_names),
|
||||||
|
}
|
||||||
|
# Mark the spine as dirty since we have to ensure it is normalized
|
||||||
|
for name in data['spine']:
|
||||||
|
self.parsed(name), self.dirty(name)
|
||||||
|
self.virtualize_resources()
|
||||||
|
self.commit()
|
||||||
|
for name in excluded_names:
|
||||||
|
os.remove(self.name_path_map[name])
|
||||||
|
with lopen(os.path.join(self.root, 'calibre-book-manifest.json'), 'wb') as f:
|
||||||
|
f.write(json.dumps(self.book_render_data, ensure_ascii=False).encode('utf-8'))
|
||||||
|
|
||||||
|
def virtualize_resources(self):
|
||||||
|
|
||||||
|
changed = set()
|
||||||
|
link_uid = self.book_render_data['link_uid']
|
||||||
|
resource_template = link_uid + '|{}|'
|
||||||
|
xlink_xpath = XPath('//*[@xl:href]')
|
||||||
|
link_xpath = XPath('//h:a[@href]')
|
||||||
|
|
||||||
|
def link_replacer(base, url):
|
||||||
|
if url.startswith('#'):
|
||||||
|
frag = urlunquote(url[1:])
|
||||||
|
if not frag:
|
||||||
|
return url
|
||||||
|
changed.add(base)
|
||||||
|
return resource_template.format(encode_url(base, frag))
|
||||||
|
purl = urlparse(url)
|
||||||
|
if purl.netloc or purl.query:
|
||||||
|
return url
|
||||||
|
if purl.scheme and purl.scheme != 'file':
|
||||||
|
return url
|
||||||
|
if not purl.path or purl.path.startswith('/'):
|
||||||
|
return url
|
||||||
|
url, frag = purl.path, purl.fragment
|
||||||
|
name = self.href_to_name(url, base)
|
||||||
|
if name:
|
||||||
|
frag = urlunquote(frag)
|
||||||
|
url = resource_template.format(encode_url(name, frag))
|
||||||
|
changed.add(base)
|
||||||
|
return url
|
||||||
|
|
||||||
|
for name, mt in self.mime_map.iteritems():
|
||||||
|
if mt in OEB_STYLES:
|
||||||
|
replaceUrls(self.parsed(name), partial(link_replacer, name))
|
||||||
|
elif mt in OEB_DOCS:
|
||||||
|
root = self.parsed(name)
|
||||||
|
rewrite_links(root, partial(link_replacer, name))
|
||||||
|
for a in link_xpath(root):
|
||||||
|
href = a.get('href')
|
||||||
|
if href.startswith(link_uid):
|
||||||
|
a.set('href', 'javascript:void(0)')
|
||||||
|
a.set('data-' + link_uid, href.split('|')[1])
|
||||||
|
else:
|
||||||
|
a.set('target', '_blank')
|
||||||
|
changed.add(name)
|
||||||
|
elif mt == 'image/svg+xml':
|
||||||
|
changed = False
|
||||||
|
xlink = XLINK('href')
|
||||||
|
for elem in xlink_xpath(self.parsed(name)):
|
||||||
|
elem.set(xlink, link_replacer(name, elem.get(xlink)))
|
||||||
|
|
||||||
|
tuple(map(self.dirty, changed))
|
||||||
|
|
||||||
|
def serialize_item(self, name):
|
||||||
|
mt = self.mime_map[name]
|
||||||
|
if mt not in OEB_DOCS:
|
||||||
|
return ContainerBase.serialize_item(self, name)
|
||||||
|
# Normalize markup
|
||||||
|
root = self.parsed(name)
|
||||||
|
for comment in tuple(root.iterdescendants(Comment)):
|
||||||
|
comment.getparent().remove(comment)
|
||||||
|
escape_cdata(root)
|
||||||
|
return tostring(root, encoding='utf-8', xml_declaration=True, with_tail=False, doctype='<!DOCTYPE html>')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
c = Container(sys.argv[-2], sys.argv[-1])
|
Loading…
x
Reference in New Issue
Block a user