Improved (but not perfected) mobi file output. Reduce cron clean up time to 2 days.

This commit is contained in:
retiefjimm
2011-03-22 19:17:41 -05:00
parent 1d1ed1ef71
commit 925324bd13
4 changed files with 184 additions and 51 deletions
+16 -6
View File
@@ -29,17 +29,27 @@ MIMETYPE = '''application/epub+zip'''
TITLE_HEADER = '''<?xml version="1.0" encoding="utf-8"?><html xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>%s - %s</title><link href="stylesheet.css" type="text/css" charset="UTF-8" rel="stylesheet"/></head><body>
<p><h7 id="lnks"><b><a id="StoryLink" href="%s">%s</a></b> by <b><a id="AuthorLink" href="%s">%s</a></b></h7></p>
<p><h3 id="lnks"><b><a id="StoryLink" href="%s">%s</a></b> by <b><a id="AuthorLink" href="%s">%s</a></b></h3></p>
'''
TITLE_ENTRY = '''<b>%s</b> %s<br />
'''
TITLE_FOOTER = '''
<br /><b>Summary:</b><br />%s<br />
</body></html>
'''
TABLE_TITLE_HEADER = TITLE_HEADER + '''
<table class="full">
'''
TITLE_ENTRY = '''<tr><td><b>%s</b></td><td>%s</td></tr>
TABLE_TITLE_ENTRY = '''<tr><td><b>%s</b></td><td>%s</td></tr>
'''
TITLE_FOOTER = '''</table>
<p><b>Summary:</b><br />%s</p>
</body></html>
'''
TABLE_TITLE_FOOTER = '''
</table>
''' + TITLE_FOOTER
CONTAINER = '''<?xml version="1.0" encoding="utf-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
+24 -17
View File
@@ -65,44 +65,50 @@ class Converter:
return out.getvalue()
def ConvertFile(self, html_file, out_file):
self._ConvertStringToFile(open(html_file).read(),
open(out_file, 'w'))
self._ConvertStringToFile(open(html_file,'rb').read(),
open(out_file, 'wb'))
def ConvertFiles(self, html_files, out_file):
html_strs = [open(f).read() for f in html_files]
self._ConvertStringsToFile(html_strs, open(out_file, 'w'))
html_strs = [open(f,'rb').read() for f in html_files]
self._ConvertStringsToFile(html_strs, open(out_file, 'wb'))
def MakeOneHTML(self, html_strs):
"""This takes a list of HTML strings and returns a big HTML file with
all contents consolidated. It constructs a table of contents and adds
anchors within the text
"""
title_html = []
toc_html = []
if self._refresh_url:
toc_html.append('<a href="%s">Update Reading List</a><br>' %
self._refresh_url)
body_html = []
titles = []
PAGE_BREAK = '<mdb;pagebreak>'
for pos, html in enumerate(html_strs):
PAGE_BREAK = '<mbp:pagebreak>'
# pull out the title page, assumed first html_strs.
htmltitle = html_strs[0]
entrytitle = _SubEntry(1, htmltitle)
title_html.append(entrytitle.Body())
toc_html.append(PAGE_BREAK)
toc_html.append('<h3>Table of Contents</h3><br />')
for pos, html in enumerate(html_strs[1:]):
entry = _SubEntry(pos+1, html)
titles.append(entry.title[:10])
toc_html.append('%s<br>' % entry.TocLink())
toc_html.append('%s<br />' % entry.TocLink())
# give some space between bodies of work.
body_html.append(PAGE_BREAK)
body_html.append(entry.Anchor())
body_html.append('<h1>%s</h1>' % entry.title)
body_html.append(entry.Body())
# TODO: this title can get way too long with RSS feeds. Not sure how to fix
header = '<html><title>Bibliorize %s GMT</title><body>' % time.ctime(
header = '<html><head><title>Bibliorize %s GMT</title></head><body>' % time.ctime(
time.time())
footer = '</body></html>'
all_html = header + '\n'.join(toc_html + body_html) + footer
all_html = header + '\n'.join(title_html + toc_html + body_html) + footer
#print "%s" % all_html.encode('utf8')
return all_html
def _ConvertStringsToFile(self, html_strs, out_file):
@@ -343,5 +349,6 @@ class Header:
if __name__ == '__main__':
import sys
m = Converter()
m.ConvertFiles(sys.argv[1:], '/tmp/test.mobi')
m = Converter(title='Testing Mobi', author='Mobi Author', publisher='mobi converter')
m.ConvertFiles(sys.argv[1:], 'test.mobi')
#m.ConvertFile(sys.argv[1], 'test.mobi')
+143 -27
View File
@@ -83,7 +83,8 @@ class TextWriter(FanficWriter):
class MobiWriter(FanficWriter):
body = ''
chapters = []
files = {}
@staticmethod
def getFormatName():
@@ -104,6 +105,9 @@ class MobiWriter(FanficWriter):
self.mobi = mobi
self.inmemory = inmemory
self.files = {}
self.chapters = []
if not self.inmemory and os.path.exists(self.fileName):
os.remove(self.fileName)
@@ -122,27 +126,140 @@ class MobiWriter(FanficWriter):
except:
return text
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:
self.files[fileName] = StringIO.StringIO()
self._writeFile(fileName, data)
def _getFilesStrings(self):
strings = []
if "title_page.xhtml" in self.files:
strings.append(self.files["title_page.xhtml"].getvalue())
del(self.files["title_page.xhtml"])
keys = self.files.keys()
keys.sort()
# Assumed all other files are chapter0000.xhtml.
for fn in keys:
strings.append(self.files[fn].getvalue())
return strings
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
title = removeEntities(title)
logging.debug("Writing chapter: %s" % title)
#title = self._printableVersion(title) #title.decode('utf-8')
text = removeEntities(text)
#text = self._printableVersion(text) #text.decode('utf-8')
# 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, 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 <p> and <br>
# tags are normalized. Doing it here seems less evil
# than hacking BeautifulSoup, but it's debatable.
text = text.replace('</p>','</p>\n').replace('<br />','<br />\n')
filename="chapter%04d.xhtml" % index
self._writeFile(filename, XHTML_START % (title, title))
self._writeFile(filename, text)
self._writeFile(filename, XHTML_END)
#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')
logging.debug("Finalising...")
# f = open(self.fileName, 'w')
# f.write(result)
# f.close()
published = self.adapter.getStoryPublished().strftime("%Y-%m-%d")
createda = self.adapter.getStoryCreated().strftime("%Y-%m-%d %H:%M:%S")
created = self.adapter.getStoryCreated().strftime("%Y-%m-%d")
updated = self.adapter.getStoryUpdated().strftime("%Y-%m-%d")
updateyy = self.adapter.getStoryUpdated().strftime("%Y")
updatemm = self.adapter.getStoryUpdated().strftime("%m")
updatedd = self.adapter.getStoryUpdated().strftime("%d")
calibre = self.adapter.getStoryUpdated().strftime("%Y-%m-%dT%H:%M:%S")
description = self.adapter.getStoryDescription()
if hasattr(description, "text"):
description = description.text
prevalue=description
try:
description = unicode(description)
except:
description=prevalue
if description is not None and len(description) > 0:
description = description.replace ('\\\'', '\'').replace('\\\"', '\"')
description = removeEntities(description)
else:
description = ' '
c = mobi.Converter(title=self.storyTitle, author=self.authorName, publisher=self.publisher)
mobidata = c.ConvertString(result)
### writing content -- title page
titleFilePath = "title_page.xhtml"
self._writeFile(titleFilePath, TITLE_HEADER % (self.authorName, self.storyTitle, self.adapter.getStoryURL(), self.storyTitle, self.adapter.getAuthorURL(), self.authorName))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Category:', self.adapter.getCategory()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Genre:', self.adapter.getGenre()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Status:', self.adapter.getStoryStatus()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Published:', published))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Updated:', updated))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Packaged:', createda))
tmpstr = self.adapter.getStoryRating() + " / " + self.adapter.getStoryUserRating()
self._writeFile(titleFilePath, TITLE_ENTRY % ('Rating Age/User:', tmpstr))
tmpstr = unicode(self.adapter.getNumChapters()) + " / " + commaGroups(unicode(self.adapter.getNumWords()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Chapters/Words:', tmpstr))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Publisher:', self.adapter.getHost()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Story ID:', self.adapter.getStoryId()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Author ID:', self.adapter.getAuthorId()))
self._writeFile(titleFilePath, TITLE_FOOTER % description )
c = mobi.Converter(title=self.storyTitle,
author=self.authorName,
publisher=self.publisher)
mobidata = c.ConvertStrings(self._getFilesStrings())
self.output.write(mobidata)
if not self.inmemory:
self.output.close()
# zipdir.toZip(filename, self.directory)
class HTMLWriter(FanficWriter):
@@ -205,7 +322,6 @@ class HTMLWriter(FanficWriter):
class EPubFanficWriter(FanficWriter):
chapters = []
files = {}
@staticmethod
@@ -360,22 +476,22 @@ class EPubFanficWriter(FanficWriter):
### writing content -- title page
titleFilePath = "OEBPS/title_page.xhtml"
self._writeFile(titleFilePath, TITLE_HEADER % (self.authorName, self.storyTitle, self.adapter.getStoryURL(), self.storyTitle, self.adapter.getAuthorURL(), self.authorName))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Category:', self.adapter.getCategory()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Genre:', self.adapter.getGenre()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Status:', self.adapter.getStoryStatus()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Published:', published))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Updated:', updated))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Packaged:', createda))
self._writeFile(titleFilePath, TABLE_TITLE_HEADER % (self.authorName, self.storyTitle, self.adapter.getStoryURL(), self.storyTitle, self.adapter.getAuthorURL(), self.authorName))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Category:', self.adapter.getCategory()))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Genre:', self.adapter.getGenre()))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Status:', self.adapter.getStoryStatus()))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Published:', published))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Updated:', updated))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Packaged:', createda))
tmpstr = self.adapter.getStoryRating() + " / " + self.adapter.getStoryUserRating()
self._writeFile(titleFilePath, TITLE_ENTRY % ('Rating Age/User:', tmpstr))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Rating Age/User:', tmpstr))
tmpstr = unicode(self.adapter.getNumChapters()) + " / " + commaGroups(unicode(self.adapter.getNumWords()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Chapters/Words:', tmpstr))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Publisher:', self.adapter.getHost()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Story ID:', self.adapter.getStoryId()))
self._writeFile(titleFilePath, TITLE_ENTRY % ('Author ID:', self.adapter.getAuthorId()))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Chapters/Words:', tmpstr))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Publisher:', self.adapter.getHost()))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Story ID:', self.adapter.getStoryId()))
self._writeFile(titleFilePath, TABLE_TITLE_ENTRY % ('Author ID:', self.adapter.getAuthorId()))
self._writeFile(titleFilePath, TITLE_FOOTER % description )
self._writeFile(titleFilePath, TABLE_TITLE_FOOTER % description )
### writing content -- opf file
opfFilePath = "OEBPS/content.opf"
+1 -1
View File
@@ -21,7 +21,7 @@ class Remover(webapp.RequestHandler):
logging.debug("Starting r3m0v3r")
user = users.get_current_user()
logging.debug("Working as user %s" % user)
theDate = datetime.date.today() - datetime.timedelta(days=7)
theDate = datetime.date.today() - datetime.timedelta(days=2)
logging.debug("Will delete stuff older than %s" % theDate)
fics = DownloadMeta.all()