# -*- coding: utf-8 -*- import os import re import sys import cgi import uuid import codecs import shutil import string import os.path import zipfile import StringIO import logging import hashlib import urllib as u import pprint as pp import urllib2 as u2 import urlparse as up import BeautifulSoup as bs import htmlentitydefs as hdefs import zipdir import html_constants from constants import * import html2text import datetime class FanficWriter: def __init__(self): pass def writeChapter(self, index, title, text): pass def finalise(self): pass class TextWriter(FanficWriter): htmlWriter = None def __init__(self, base, adapter, inmemory=False, compress=False): self.htmlWriter = HTMLWriter(base, adapter, True, False) def writeChapter(self, index, title, text): self.htmlWriter.writeChapter(index, title, text) def finalise(self): self.htmlWriter.finalise() self.output = StringIO.StringIO() self.output.write(html2text.html2text(self.htmlWriter.output.getvalue().decode('utf-8')).encode('utf-8')) self.name = self.htmlWriter.name class HTMLWriter(FanficWriter): body = '' def __init__(self, base, adapter, inmemory=False, compress=False): self.basePath = base self.storyTitle = removeEntities(adapter.getStoryName()) self.name = makeAcceptableFilename(adapter.getOutputName()) self.fileName = self.basePath + '/' + self.name + '.html' self.authorName = removeEntities(adapter.getAuthorName()) self.adapter = adapter self.inmemory = inmemory if not self.inmemory and os.path.exists(self.fileName): os.remove(self.fileName) if self.inmemory: self.output = StringIO.StringIO() else: self.output = open(self.fileName, 'w') self.xhtmlTemplate = string.Template(html_constants.XHTML_START) self.chapterStartTemplate = string.Template(html_constants.XHTML_CHAPTER_START) def _printableVersion(self, text): try: d = text.decode('utf-8') return d except: return text def writeChapter(self, index, title, text): title = self._printableVersion(title) #title.decode('utf-8') text = self._printableVersion(text) #text.decode('utf-8') self.body = self.body + '\n' + self.chapterStartTemplate.substitute({'chapter' : title}) self.body = self.body + '\n' + text def finalise(self): html = self.xhtmlTemplate.substitute({'title' : self.storyTitle, 'author' : self.authorName, 'body' : self.body}) soup = bs.BeautifulSoup(html) result = soup.__str__('utf8') # f = open(self.fileName, 'w') # f.write(result) # f.close() self.output.write(result) if not self.inmemory: self.output.close() class EPubFanficWriter(FanficWriter): chapters = [] files = {} def _writeFile(self, fileName, data): #logging.debug('_writeFile(`%s`, data)' % fileName) if fileName in self.files: try: d = data.decode('utf-8') except UnicodeEncodeError, e: d = data self.files[fileName].write(d) else: if self.inmemory: self.files[fileName] = StringIO.StringIO() else: self.files[fileName] = open(self.directory + '/' + fileName, 'w') self._writeFile(fileName, data) def _closeFiles(self): if not self.inmemory: for f in self.files: self.files[f].close() def __init__(self, base, adapter, inmemory=False, compress=True): self.basePath = base self.storyTitle = removeEntities(adapter.getStoryName()) self.name = makeAcceptableFilename(adapter.getOutputName()) self.directory = self.basePath + '/' + self.name self.authorName = removeEntities(adapter.getAuthorName()) self.inmemory = inmemory self.adapter = adapter self.files = {} self.chapters = [] if not self.inmemory: self.inmemory = True self.writeToFile = True else: self.writeToFile = False if not self.inmemory: if os.path.exists(self.directory): shutil.rmtree(self.directory) os.mkdir(self.directory) os.mkdir(self.directory + '/META-INF') os.mkdir(self.directory + '/OEBPS') self._writeFile('mimetype', MIMETYPE) self._writeFile('META-INF/container.xml', CONTAINER) self._writeFile('OEBPS/stylesheet.css', CSS) def writeChapter(self, index, title, text): title = removeEntities(title) logging.debug("Writing chapter: %s" % title) fileName="chapter%04d.xhtml" % index filePath = self.directory + "/OEBPS/" + fileName fn = 'OEBPS/' + fileName # f = open(filePath, 'w') text = removeEntities(text) # BeautifulStoneSoup doesn't have any selfClosingTags by default. # hr & br needs to be if they're going to work. # Some stories do use multiple br tags as their section breaks... self.soup = bs.BeautifulStoneSoup(text.decode('utf-8'), selfClosingTags=('br','hr')) allTags = self.soup.findAll(recursive=True) for t in allTags: for attr in t._getAttrMap().keys(): if attr not in acceptable_attributes: del t[attr] # these are not acceptable strict XHTML. But we do already have # CSS classes of the same names defined in constants.py if t.name in ('u'): t['class']=t.name t.name='span' if t.name in ('center'): t['class']=t.name t.name='div' # removes paired, but empty tags. if t.string != None and len(t.string.strip()) == 0 : t.extract() text = self.soup.__str__('utf8') # ffnet(& maybe others) gives the whole chapter text # as one line. This causes problems for nook(at # least) when the chapter size starts getting big # (200k+) Using Soup's prettify() messes up italics # and such. Done after soup extract so
and
# tags are normalized. Doing it here seems less evil
# than hacking BeautifulSoup, but it's debatable.
text = text.replace('