1# -*- coding: utf-8 -*- 2 3 4__license__ = 'GPL 3' 5__copyright__ = '2010, Li Fanxi <lifanxi@freemindworld.com>' 6__docformat__ = 'restructuredtext en' 7 8import os 9 10from calibre.customize.conversion import InputFormatPlugin 11from calibre.ptempfile import TemporaryDirectory 12from calibre.utils.filenames import ascii_filename 13 14HTML_TEMPLATE = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>%s</title></head><body>\n%s\n</body></html>' 15 16 17def html_encode(s): 18 return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''').replace('\n', '<br/>').replace(' ', ' ') # noqa 19 20 21class SNBInput(InputFormatPlugin): 22 23 name = 'SNB Input' 24 author = 'Li Fanxi' 25 description = _('Convert SNB files to OEB') 26 file_types = {'snb'} 27 commit_name = 'snb_input' 28 29 options = set() 30 31 def convert(self, stream, options, file_ext, log, 32 accelerators): 33 import uuid 34 35 from calibre.ebooks.oeb.base import DirContainer 36 from calibre.ebooks.snb.snbfile import SNBFile 37 from calibre.utils.xml_parse import safe_xml_fromstring 38 39 log.debug("Parsing SNB file...") 40 snbFile = SNBFile() 41 try: 42 snbFile.Parse(stream) 43 except: 44 raise ValueError("Invalid SNB file") 45 if not snbFile.IsValid(): 46 log.debug("Invalid SNB file") 47 raise ValueError("Invalid SNB file") 48 log.debug("Handle meta data ...") 49 from calibre.ebooks.conversion.plumber import create_oebbook 50 oeb = create_oebbook(log, None, options, 51 encoding=options.input_encoding, populate=False) 52 meta = snbFile.GetFileStream('snbf/book.snbf') 53 if meta is not None: 54 meta = safe_xml_fromstring(meta) 55 l = {'title' : './/head/name', 56 'creator' : './/head/author', 57 'language' : './/head/language', 58 'generator': './/head/generator', 59 'publisher': './/head/publisher', 60 'cover' : './/head/cover', } 61 d = {} 62 for item in l: 63 node = meta.find(l[item]) 64 if node is not None: 65 d[item] = node.text if node.text is not None else '' 66 else: 67 d[item] = '' 68 69 oeb.metadata.add('title', d['title']) 70 oeb.metadata.add('creator', d['creator'], attrib={'role':'aut'}) 71 oeb.metadata.add('language', d['language'].lower().replace('_', '-')) 72 oeb.metadata.add('generator', d['generator']) 73 oeb.metadata.add('publisher', d['publisher']) 74 if d['cover'] != '': 75 oeb.guide.add('cover', 'Cover', d['cover']) 76 77 bookid = str(uuid.uuid4()) 78 oeb.metadata.add('identifier', bookid, id='uuid_id', scheme='uuid') 79 for ident in oeb.metadata.identifier: 80 if 'id' in ident.attrib: 81 oeb.uid = oeb.metadata.identifier[0] 82 break 83 84 with TemporaryDirectory('_snb2oeb', keep=True) as tdir: 85 log.debug('Process TOC ...') 86 toc = snbFile.GetFileStream('snbf/toc.snbf') 87 oeb.container = DirContainer(tdir, log) 88 if toc is not None: 89 toc = safe_xml_fromstring(toc) 90 i = 1 91 for ch in toc.find('.//body'): 92 chapterName = ch.text 93 chapterSrc = ch.get('src') 94 fname = 'ch_%d.htm' % i 95 data = snbFile.GetFileStream('snbc/' + chapterSrc) 96 if data is None: 97 continue 98 snbc = safe_xml_fromstring(data) 99 lines = [] 100 for line in snbc.find('.//body'): 101 if line.tag == 'text': 102 lines.append('<p>%s</p>' % html_encode(line.text)) 103 elif line.tag == 'img': 104 lines.append('<p><img src="%s" /></p>' % html_encode(line.text)) 105 with open(os.path.join(tdir, fname), 'wb') as f: 106 f.write((HTML_TEMPLATE % (chapterName, '\n'.join(lines))).encode('utf-8', 'replace')) 107 oeb.toc.add(ch.text, fname) 108 id, href = oeb.manifest.generate(id='html', 109 href=ascii_filename(fname)) 110 item = oeb.manifest.add(id, href, 'text/html') 111 item.html_input_href = fname 112 oeb.spine.add(item, True) 113 i = i + 1 114 imageFiles = snbFile.OutputImageFiles(tdir) 115 for f, m in imageFiles: 116 id, href = oeb.manifest.generate(id='image', 117 href=ascii_filename(f)) 118 item = oeb.manifest.add(id, href, m) 119 item.html_input_href = f 120 121 return oeb 122