mirror of
https://github.com/wassname/FanFicFare.git
synced 2026-09-10 11:40:24 +08:00
Make just about all the output formatting customizable.
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
import re
|
||||
import os.path
|
||||
import datetime
|
||||
import string
|
||||
import StringIO
|
||||
import zipfile
|
||||
from zipfile import ZipFile, ZIP_DEFLATED
|
||||
@@ -101,6 +102,22 @@ class BaseStoryWriter(Configurable):
|
||||
names as Story.metadata, but ENTRY should use label and value.
|
||||
"""
|
||||
if self.getConfig("include_titlepage"):
|
||||
|
||||
if self.hasConfig("titlepage_start"):
|
||||
START = string.Template(self.getConfig("titlepage_start"))
|
||||
|
||||
if self.hasConfig("titlepage_entry"):
|
||||
ENTRY = string.Template(self.getConfig("titlepage_entry"))
|
||||
|
||||
if self.hasConfig("titlepage_end"):
|
||||
END = string.Template(self.getConfig("titlepage_end"))
|
||||
|
||||
if self.hasConfig("titlepage_wide_entry"):
|
||||
WIDE_ENTRY = string.Template(self.getConfig("titlepage_wide_entry"))
|
||||
|
||||
if self.hasConfig("titlepage_no_title_entry"):
|
||||
NO_TITLE_ENTRY = string.Template(self.getConfig("titlepage_no_title_entry"))
|
||||
|
||||
self._write(out,START.substitute(self.story.getAllMetadata()))
|
||||
|
||||
if WIDE_ENTRY==None:
|
||||
@@ -132,6 +149,7 @@ class BaseStoryWriter(Configurable):
|
||||
TEMPLATE= NO_TITLE_ENTRY
|
||||
|
||||
self._write(out,TEMPLATE.substitute({'label':label,
|
||||
'id':entry,
|
||||
'value':self.story.getMetadata(entry)}))
|
||||
else:
|
||||
self._write(out, entry)
|
||||
@@ -146,11 +164,22 @@ class BaseStoryWriter(Configurable):
|
||||
"""
|
||||
# Only do TOC if there's more than one chapter and it's configured.
|
||||
if len(self.story.getChapters()) > 1 and self.getConfig("include_tocpage") and not self.metaonly :
|
||||
if self.hasConfig("tocpage_start"):
|
||||
START = string.Template(self.getConfig("tocpage_start"))
|
||||
|
||||
if self.hasConfig("tocpage_entry"):
|
||||
ENTRY = string.Template(self.getConfig("tocpage_entry"))
|
||||
|
||||
if self.hasConfig("tocpage_end"):
|
||||
END = string.Template(self.getConfig("tocpage_end"))
|
||||
|
||||
self._write(out,START.substitute(self.story.getAllMetadata()))
|
||||
|
||||
for index, (title,html) in enumerate(self.story.getChapters(fortoc=True)):
|
||||
if html:
|
||||
self._write(out,ENTRY.substitute({'chapter':title, 'index':"%04d"%(index+1)}))
|
||||
self._write(out,ENTRY.substitute({'chapter':title,
|
||||
'number':index+1,
|
||||
'index':"%04d"%(index+1)}))
|
||||
|
||||
self._write(out,END.substitute(self.story.getAllMetadata()))
|
||||
|
||||
|
||||
@@ -151,8 +151,16 @@ ${value}<br />
|
||||
<h3>Update Log</h3>
|
||||
''')
|
||||
|
||||
self.EPUB_LOG_UPDATE_START = string.Template('''
|
||||
<p class='log_entry'>
|
||||
''')
|
||||
|
||||
self.EPUB_LOG_ENTRY = string.Template('''
|
||||
<b>${label}:</b> <span id="${id}">${value}</span>
|
||||
''')
|
||||
|
||||
self.EPUB_LOG_UPDATE_END = string.Template('''
|
||||
</p><hr />
|
||||
''')
|
||||
|
||||
self.EPUB_LOG_PAGE_END = string.Template('''
|
||||
@@ -160,30 +168,52 @@ ${value}<br />
|
||||
</html>
|
||||
''')
|
||||
|
||||
self.EPUB_LOG_PAGE_END = string.Template('''
|
||||
</body>
|
||||
</html>
|
||||
''')
|
||||
|
||||
self.EPUB_COVER = string.Template('''
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head><title>Cover</title><style type="text/css" title="override_css">
|
||||
@page {padding: 0pt; margin:0pt}
|
||||
body { text-align: center; padding:0pt; margin: 0pt; }
|
||||
div { margin: 0pt; padding: 0pt; }
|
||||
</style></head><body><div>
|
||||
<img src="${coverimg}" alt="cover"/>
|
||||
</div></body></html>
|
||||
''')
|
||||
|
||||
def writeLogPage(self, out):
|
||||
"""
|
||||
XXX
|
||||
|
||||
|
||||
Write the log page, but only include entries that there's
|
||||
metadata for. START, ENTRY and END are expected to already by
|
||||
metadata for. START, ENTRY and END are expected to already be
|
||||
string.Template(). START and END are expected to use the same
|
||||
names as Story.metadata, but ENTRY should use id, label and value.
|
||||
"""
|
||||
if self.getConfig("include_logpage"):
|
||||
|
||||
if self.hasConfig("logpage_start"):
|
||||
START = string.Template(self.getConfig("logpage_start"))
|
||||
else:
|
||||
START = self.EPUB_LOG_PAGE_START
|
||||
|
||||
if self.hasConfig("logpage_end"):
|
||||
END = string.Template(self.getConfig("logpage_end"))
|
||||
else:
|
||||
END = self.EPUB_LOG_PAGE_END
|
||||
|
||||
# if there's a self.story.logfile, there's an existing log
|
||||
# to add to.
|
||||
if self.story.logfile:
|
||||
print("existing logfile found, appending")
|
||||
print("existing data:%s"%self._getLastLogData(self.story.logfile))
|
||||
logging.debug("existing logfile found, appending")
|
||||
logging.debug("existing data:%s"%self._getLastLogData(self.story.logfile))
|
||||
replace_string = "</body>" # "</h3>"
|
||||
self._write(out,self.story.logfile.replace(replace_string,self._makeLogEntry(self._getLastLogData(self.story.logfile))+replace_string))
|
||||
else:
|
||||
# otherwise, write a new one.
|
||||
self._write(out,self.EPUB_LOG_PAGE_START.substitute(self.story.getAllMetadata()))
|
||||
self._write(out,START.substitute(self.story.getAllMetadata()))
|
||||
self._write(out,self._makeLogEntry())
|
||||
self._write(out,self.EPUB_LOG_PAGE_END.substitute(self.story.getAllMetadata()))
|
||||
self._write(out,END.substitute(self.story.getAllMetadata()))
|
||||
|
||||
# self parsing instead of Soup because it should be simple and not
|
||||
# worth the overhead.
|
||||
@@ -206,7 +236,22 @@ ${value}<br />
|
||||
return values
|
||||
|
||||
def _makeLogEntry(self, oldvalues={}):
|
||||
retval = "<p class='log_entry'>"
|
||||
if self.hasConfig("logpage_update_start"):
|
||||
START = string.Template(self.getConfig("logpage_update_start"))
|
||||
else:
|
||||
START = self.EPUB_LOG_UPDATE_START
|
||||
|
||||
if self.hasConfig("logpage_entry"):
|
||||
ENTRY = string.Template(self.getConfig("logpage_entry"))
|
||||
else:
|
||||
ENTRY = self.EPUB_LOG_ENTRY
|
||||
|
||||
if self.hasConfig("logpage_update_end"):
|
||||
END = string.Template(self.getConfig("logpage_update_end"))
|
||||
else:
|
||||
END = self.EPUB_LOG_UPDATE_END
|
||||
|
||||
retval = START.substitute(self.story.getAllMetadata())
|
||||
|
||||
for entry in self.getConfigList("logpage_entries") + self.getConfigList("extra_logpage_entries"):
|
||||
if self.isValidMetaEntry(entry):
|
||||
@@ -221,16 +266,16 @@ ${value}<br />
|
||||
label="%s"%entry.title()
|
||||
logging.debug("No known label for %s, fallback to '%s'"%(entry,label))
|
||||
|
||||
retval = retval + self.EPUB_LOG_ENTRY.substitute({'id':entry,
|
||||
'label':label,
|
||||
'value':val})
|
||||
retval = retval + ENTRY.substitute({'id':entry,
|
||||
'label':label,
|
||||
'value':val})
|
||||
else:
|
||||
# could be useful for introducing extra text, but
|
||||
# mostly it makes it easy to tell when you get the
|
||||
# keyword wrong.
|
||||
retval = retval + entry
|
||||
|
||||
retval = retval + "</p><hr />"
|
||||
retval = retval + END.substitute(self.story.getAllMetadata())
|
||||
|
||||
if self.getConfig('replace_hr'):
|
||||
retval = retval.replace("<hr />","<div class='center'>* * *</div>")
|
||||
@@ -429,16 +474,12 @@ ${value}<br />
|
||||
"title":"Cover",
|
||||
"href":"OEBPS/cover.xhtml"}))
|
||||
|
||||
if self.hasConfig("cover_content"):
|
||||
COVER = string.Template(self.getConfig("cover_content"))
|
||||
else:
|
||||
COVER = self.EPUB_COVER
|
||||
coverIO = StringIO.StringIO()
|
||||
coverIO.write('''
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head><title>Cover</title><style type="text/css" title="override_css">
|
||||
@page {padding: 0pt; margin:0pt}
|
||||
body { text-align: center; padding:0pt; margin: 0pt; }
|
||||
div { margin: 0pt; padding: 0pt; }
|
||||
</style></head><body><div>
|
||||
<img src="%s" alt="cover"/>
|
||||
</div></body></html>
|
||||
'''%self.story.cover)
|
||||
coverIO.write(COVER.substitute(dict(self.story.getAllMetadata().items()+{'coverimg':self.story.cover}.items())))
|
||||
|
||||
if self.getConfig("include_titlepage"):
|
||||
items.append(("title_page","OEBPS/title_page.xhtml","application/xhtml+xml","Title Page"))
|
||||
@@ -588,11 +629,22 @@ div { margin: 0pt; padding: 0pt; }
|
||||
if logpageIO.getvalue(): # will be false if no log page.
|
||||
outputepub.writestr("OEBPS/log_page.xhtml",logpageIO.getvalue())
|
||||
logpageIO.close()
|
||||
|
||||
if self.hasConfig('chapter_start'):
|
||||
CHAPTER_START = string.Template(self.getConfig("chapter_start"))
|
||||
else:
|
||||
CHAPTER_START = self.EPUB_CHAPTER_START
|
||||
|
||||
if self.hasConfig('chapter_end'):
|
||||
CHAPTER_END = string.Template(self.getConfig("chapter_end"))
|
||||
else:
|
||||
CHAPTER_END = self.EPUB_CHAPTER_END
|
||||
|
||||
for index, (title,html) in enumerate(self.story.getChapters()):
|
||||
if html:
|
||||
logging.debug('Writing chapter text for: %s' % title)
|
||||
fullhtml = self.EPUB_CHAPTER_START.substitute({'chapter':title, 'index':index+1}) + html + self.EPUB_CHAPTER_END.substitute({'chapter':title, 'index':index+1})
|
||||
vals={'chapter':title, 'index':"%04d"%(index+1), 'number':index+1}
|
||||
fullhtml = CHAPTER_START.substitute(vals) + html + CHAPTER_END.substitute(vals)
|
||||
# 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
|
||||
|
||||
@@ -75,6 +75,8 @@ ${output_css}
|
||||
<a name="section${index}"><h2>${chapter}</h2></a>
|
||||
''')
|
||||
|
||||
self.HTML_CHAPTER_END = string.Template('')
|
||||
|
||||
self.HTML_FILE_END = string.Template('''
|
||||
</body>
|
||||
</html>''')
|
||||
@@ -82,7 +84,17 @@ ${output_css}
|
||||
|
||||
def writeStoryImpl(self, out):
|
||||
|
||||
self._write(out,self.HTML_FILE_START.substitute(self.story.getAllMetadata()))
|
||||
if self.hasConfig('file_start'):
|
||||
FILE_START = string.Template(self.getConfig("file_start"))
|
||||
else:
|
||||
FILE_START = self.HTML_FILE_START
|
||||
|
||||
if self.hasConfig('file_end'):
|
||||
FILE_END = string.Template(self.getConfig("file_end"))
|
||||
else:
|
||||
FILE_END = self.HTML_FILE_END
|
||||
|
||||
self._write(out,FILE_START.substitute(self.story.getAllMetadata()))
|
||||
|
||||
self.writeTitlePage(out,
|
||||
self.HTML_TITLE_PAGE_START,
|
||||
@@ -94,10 +106,22 @@ ${output_css}
|
||||
self.HTML_TOC_ENTRY,
|
||||
self.HTML_TOC_PAGE_END)
|
||||
|
||||
if self.hasConfig('chapter_start'):
|
||||
CHAPTER_START = string.Template(self.getConfig("chapter_start"))
|
||||
else:
|
||||
CHAPTER_START = self.HTML_CHAPTER_START
|
||||
|
||||
if self.hasConfig('chapter_end'):
|
||||
CHAPTER_END = string.Template(self.getConfig("chapter_end"))
|
||||
else:
|
||||
CHAPTER_END = self.HTML_CHAPTER_END
|
||||
|
||||
for index, (title,html) in enumerate(self.story.getChapters()):
|
||||
if html:
|
||||
logging.debug('Writing chapter text for: %s' % title)
|
||||
self._write(out,self.HTML_CHAPTER_START.substitute({'chapter':title, 'index':"%04d"%(index+1)}))
|
||||
vals={'chapter':title, 'index':"%04d"%(index+1), 'number':index+1}
|
||||
self._write(out,CHAPTER_START.substitute(vals))
|
||||
self._write(out,html)
|
||||
self._write(out,CHAPTER_END.substitute(vals))
|
||||
|
||||
self._write(out,self.HTML_FILE_END.substitute(self.story.getAllMetadata()))
|
||||
self._write(out,FILE_END.substitute(self.story.getAllMetadata()))
|
||||
|
||||
@@ -88,27 +88,6 @@ ${value}<br />
|
||||
self.MOBI_TABLE_TITLE_PAGE_END = string.Template('''
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
''')
|
||||
|
||||
self.MOBI_TOC_PAGE_START = string.Template('''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>${title} by ${author}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h3>Table of Contents</h3>
|
||||
''')
|
||||
|
||||
self.MOBI_TOC_ENTRY = string.Template('''
|
||||
<a href="file${index}.xhtml">${chapter}</a><br />
|
||||
''')
|
||||
|
||||
self.MOBI_TOC_PAGE_END = string.Template('''
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
''')
|
||||
@@ -169,10 +148,21 @@ ${value}<br />
|
||||
# files.append(tocpageIO.getvalue())
|
||||
# tocpageIO.close()
|
||||
|
||||
if self.hasConfig('chapter_start'):
|
||||
CHAPTER_START = string.Template(self.getConfig("chapter_start"))
|
||||
else:
|
||||
CHAPTER_START = self.MOBI_CHAPTER_START
|
||||
|
||||
if self.hasConfig('chapter_end'):
|
||||
CHAPTER_END = string.Template(self.getConfig("chapter_end"))
|
||||
else:
|
||||
CHAPTER_END = self.MOBI_CHAPTER_END
|
||||
|
||||
for index, (title,html) in enumerate(self.story.getChapters()):
|
||||
if html:
|
||||
logging.debug('Writing chapter text for: %s' % title)
|
||||
fullhtml = self.MOBI_CHAPTER_START.substitute({'chapter':title, 'index':index+1}) + html + self.MOBI_CHAPTER_END.substitute({'chapter':title, 'index':index+1})
|
||||
vals={'chapter':title, 'index':"%04d"%(index+1), 'number':index+1}
|
||||
fullhtml = CHAPTER_START.substitute(vals) + html + CHAPTER_END.substitute(vals)
|
||||
# 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
|
||||
|
||||
@@ -98,6 +98,7 @@ ${chapter}
|
||||
\t${chapter}
|
||||
|
||||
''')
|
||||
self.TEXT_CHAPTER_END = string.Template(u'')
|
||||
|
||||
self.TEXT_FILE_END = string.Template(u'''
|
||||
|
||||
@@ -114,7 +115,17 @@ End file.
|
||||
|
||||
wrapout = KludgeStringIO()
|
||||
|
||||
wrapout.write(self.TEXT_FILE_START.substitute(self.story.getAllMetadata()))
|
||||
if self.hasConfig("file_start"):
|
||||
FILE_START = string.Template(self.getConfig("file_start"))
|
||||
else:
|
||||
FILE_START = self.TEXT_FILE_START
|
||||
|
||||
if self.hasConfig("file_end"):
|
||||
FILE_END = string.Template(self.getConfig("file_end"))
|
||||
else:
|
||||
FILE_END = self.TEXT_FILE_END
|
||||
|
||||
wrapout.write(FILE_START.substitute(self.story.getAllMetadata()))
|
||||
|
||||
self.writeTitlePage(wrapout,
|
||||
self.TEXT_TITLE_PAGE_START,
|
||||
@@ -133,13 +144,25 @@ End file.
|
||||
|
||||
self._write(out,self.lineends(self.wraplines(towrap)))
|
||||
|
||||
if self.hasConfig('chapter_start'):
|
||||
CHAPTER_START = string.Template(self.getConfig("chapter_start"))
|
||||
else:
|
||||
CHAPTER_START = self.TEXT_CHAPTER_START
|
||||
|
||||
if self.hasConfig('chapter_end'):
|
||||
CHAPTER_END = string.Template(self.getConfig("chapter_end"))
|
||||
else:
|
||||
CHAPTER_END = self.TEXT_CHAPTER_END
|
||||
|
||||
for index, (title,html) in enumerate(self.story.getChapters()):
|
||||
if html:
|
||||
logging.debug('Writing chapter text for: %s' % title)
|
||||
self._write(out,self.lineends(self.wraplines(removeAllEntities(self.TEXT_CHAPTER_START.substitute({'chapter':title, 'index':index+1})))))
|
||||
vals={'chapter':title, 'index':"%04d"%(index+1), 'number':index+1}
|
||||
self._write(out,self.lineends(self.wraplines(removeAllEntities(CHAPTER_START.substitute(vals)))))
|
||||
self._write(out,self.lineends(html2text(html,wrap_width=self.wrap_width)))
|
||||
self._write(out,self.lineends(self.wraplines(removeAllEntities(CHAPTER_END.substitute(vals)))))
|
||||
|
||||
self._write(out,self.lineends(self.wraplines(self.TEXT_FILE_END.substitute(self.story.getAllMetadata()))))
|
||||
self._write(out,self.lineends(self.wraplines(FILE_END.substitute(self.story.getAllMetadata()))))
|
||||
|
||||
def wraplines(self, text):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user