From 50b80b6d6839b9a65d3cc40f5653c57d53f336d9 Mon Sep 17 00:00:00 2001
From: Jim Miller http://test1.com?sid=667 - raises FailedToDownload on chapter 1 http://test1.com?sid=668 - raises FailedToLogin unless username='Me' http://test1.com?sid=669 - Succeeds with Updated Date=now http://test1.com?sid=670 - Succeeds, but applies slow_down_sleep_time And other storyId will succeed with the same output. '
+ else:
+ line_splitter = '\n'
+ line_joiner = ' tags with HTML-ified text.'''
+ pres = self._soup.findAll('pre')
+ for pre in pres:
+ pre.replaceWith(self._FixPreContents(str(pre.contents[0])))
+
+ def _FixPreContents(self, text):
+ if self.unfill:
+ line_splitter = '\n\n'
+ line_joiner = '
'
+ lines = []
+ for line in text.split(line_splitter):
+ lines.append(self.WHITESPACE_RE.subn(' ', line)[0])
+ return line_joiner.join(lines)
+
+ def _RemoveUnsupported(self):
+ '''Remove any tags which the kindle cannot handle.'''
+ # TODO(chatham): tags to script?
+ unsupported_tags = ('script', 'style')
+ for tag_type in unsupported_tags:
+ for element in self._soup.findAll(tag_type):
+ element.extract()
+
+ def RenameAnchors(self, prefix):
+ '''Rename every internal anchor to have the given prefix, then
+ return the contents of the body tag.'''
+ for anchor in self._soup.findAll('a', href=re.compile('^#')):
+ anchor['href'] = '#' + prefix + anchor['href'][1:]
+ for a in self._soup.findAll('a'):
+ if a.get('name'):
+ a['name'] = prefix + a['name']
+
+ # TODO(chatham): figure out how to fix this. sometimes body comes out
+ # as NoneType.
+ content = []
+ if self._soup.body is not None:
+ content = [unicode(c) for c in self._soup.body.contents]
+ return '\n'.join(content)
+
+ def CleanHtml(self):
+ # TODO(chatham): fix_html_br, fix_html
+ self._RemoveUnsupported()
+ self._StubInternalAnchors()
+ self._FixPreTags()
+ return self._ReplaceAnchorStubs()
+
+
+if __name__ == '__main__':
+ FILE ='/tmp/documentation.html'
+ #FILE = '/tmp/multipre.html'
+ FILE = '/tmp/view.html'
+ import codecs
+ d = open(FILE).read()
+ h = HtmlProcessor(d)
+ s = h.CleanHtml()
+ #print s
diff --git a/fanficdownloader/mobi.py b/fanficdownloader/mobi.py
new file mode 100644
index 0000000..4748e20
--- /dev/null
+++ b/fanficdownloader/mobi.py
@@ -0,0 +1,384 @@
+#!/usr/bin/python
+# Copyright(c) 2009 Andrew Chatham and Vijay Pandurangan
+
+
+import StringIO
+import struct
+import time
+import random
+import logging
+
+from html import HtmlProcessor
+
+# http://wiki.mobileread.com/wiki/MOBI
+# http://membres.lycos.fr/microfirst/palm/pdb.html
+
+encoding = {
+ 'UTF-8' : 65001,
+ 'latin-1' : 1252,
+}
+
+languages = {"en-us" : 0x0409,
+ "sv" : 0x041d,
+ "fi" : 0x000b,
+ "en" : 0x0009,
+ "en-gb" : 0x0809}
+
+def ToHex(s):
+ v = ['%.2x' % ord(c) for c in s]
+ return ' '.join(v)
+
+class _SubEntry:
+ def __init__(self, pos, html_data):
+ self.pos = pos
+ self.html = HtmlProcessor(html_data)
+ self.title = self.html.title
+ self._name = 'mobi_article_%d' % pos
+ if not self.title:
+ self.title = 'Article %d' % self.pos
+
+ def TocLink(self):
+ return '%.80s' % (self._name, self.title)
+
+ def Anchor(self):
+ return '' % self._name
+
+ def Body(self):
+ return self.html.RenameAnchors(self._name + '_')
+
+class Converter:
+ def __init__(self, refresh_url='', title='Unknown', author='Unknown', publisher='Unknown'):
+ self._header = Header()
+ self._header.SetTitle(title)
+ self._header.SetAuthor(author)
+ self._header.SetPublisher(publisher)
+ self._refresh_url = refresh_url
+
+ def ConvertString(self, s):
+ out = StringIO.StringIO()
+ self._ConvertStringToFile(s, out)
+ return out.getvalue()
+
+ def ConvertStrings(self, html_strs):
+ out = StringIO.StringIO()
+ self._ConvertStringsToFile(html_strs, out)
+ return out.getvalue()
+
+ def ConvertFile(self, html_file, out_file):
+ self._ConvertStringToFile(open(html_file,'rb').read(),
+ open(out_file, 'wb'))
+
+ def ConvertFiles(self, html_files, out_file):
+ 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 = []
+ body_html = []
+
+ PAGE_BREAK = 'Table of Contents
')
+
+ for pos, html in enumerate(html_strs[1:]):
+ entry = _SubEntry(pos+1, html)
+ toc_html.append('%s
' % entry.TocLink())
+
+ # give some space between bodies of work.
+ body_html.append(PAGE_BREAK)
+
+ body_html.append(entry.Anchor())
+
+ body_html.append(entry.Body())
+
+ # TODO: this title can get way too long with RSS feeds. Not sure how to fix
+ # cheat slightly and use the code to set filepos in references.
+ header = '''
+
+${title} by ${author}
+
+''')
+
+ self.MOBI_TITLE_PAGE_END = string.Template('''
+${title} by ${author}
+
+''')
+
+ self.MOBI_TABLE_TITLE_ENTRY = string.Template('''
+
+
+
+
+''')
+
+ self.MOBI_TOC_PAGE_START = string.Template('''
+
+
+
+
+''')
+
+ self.MOBI_TABLE_TITLE_WIDE_ENTRY = string.Template('''
+${label}: ${value}
+''')
+
+ self.MOBI_TABLE_TITLE_PAGE_END = string.Template('''
+${label}: ${value} Table of Contents
+''')
+
+ self.MOBI_TOC_ENTRY = string.Template('''
+${chapter}
+''')
+
+ self.MOBI_TOC_PAGE_END = string.Template('''
+${chapter}
+''')
+
+ self.MOBI_CHAPTER_END = string.Template('''
+
+
+''')
+
+ def getMetadata(self,key):
+ return stripHTML(self.story.getMetadata(key))
+
+ def writeStoryImpl(self, out):
+
+ files = []
+
+ # write title page.
+ if self.getConfig("titlepage_use_table"):
+ TITLE_PAGE_START = self.MOBI_TABLE_TITLE_PAGE_START
+ TITLE_ENTRY = self.MOBI_TABLE_TITLE_ENTRY
+ WIDE_TITLE_ENTRY = self.MOBI_TABLE_TITLE_WIDE_ENTRY
+ TITLE_PAGE_END = self.MOBI_TABLE_TITLE_PAGE_END
+ else:
+ TITLE_PAGE_START = self.MOBI_TITLE_PAGE_START
+ TITLE_ENTRY = self.MOBI_TITLE_ENTRY
+ WIDE_TITLE_ENTRY = self.MOBI_TITLE_ENTRY # same, only wide in tables.
+ TITLE_PAGE_END = self.MOBI_TITLE_PAGE_END
+
+ titlepageIO = StringIO.StringIO()
+ self.writeTitlePage(out=titlepageIO,
+ START=TITLE_PAGE_START,
+ ENTRY=TITLE_ENTRY,
+ WIDE_ENTRY=WIDE_TITLE_ENTRY,
+ END=TITLE_PAGE_END)
+ if titlepageIO.getvalue(): # will be false if no title page.
+ files.append(titlepageIO.getvalue())
+ titlepageIO.close()
+
+ ## MOBI always has a TOC injected by mobi.py because there's
+ ## no meta-data TOC.
+ # # write toc page.
+ # tocpageIO = StringIO.StringIO()
+ # self.writeTOCPage(tocpageIO,
+ # self.MOBI_TOC_PAGE_START,
+ # self.MOBI_TOC_ENTRY,
+ # self.MOBI_TOC_PAGE_END)
+ # if tocpageIO.getvalue(): # will be false if no toc page.
+ # files.append(tocpageIO.getvalue())
+ # tocpageIO.close()
+
+ for index, (title,html) in enumerate(self.story.getChapters()):
+ 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})
+ # 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+)
+ fullhtml = fullhtml.replace('
- Mobi support (for Kindle) is only via EPub conversion in this version. + The same (rather crude) Mobi support (for Kindle) that we + had before is restored. Mobi via EPub conversion is still + available and provides better output.
If you have any problems with this new version, please @@ -81,12 +83,12 @@ EPub HTML Plain Text + Mobi(Kindle)
For most readers, including Sony Reader, Nook and iPad, use EPub.
-For Kindle and other Mobi readers, select EPub and use the Convert link when it's finished.
{% if fic.completed %}
- Download {{ fic.title }}
- by {{ fic.author }} ({{ fic.format }})
- {% if fic.escaped_url %}
- Convert {{ fic.title }} to other formats
+ Download {{ fic.title }}
+ by {{ fic.author }} ({{ fic.format }})
{% endif %}
+ {% if not fic.completed and not fic.failure %}
+ Processing {{ fic.title }}
+ by {{ fic.author }} ({{ fic.format }})
{% endif %}
{% if fic.failure %}
-
+ {% if fic.completed %} +
Your fic has finished processing and you can download it now.
+ Download {{ fic.title }} + by {{ fic.author }} ({{ fic.format }}) + {% endif %} + {% if fic.failure %} + {{ fic.failure }} + {% endif %} + {% if not fic.completed and not fic.failure %} + Processing {{ fic.title }} + by {{ fic.author }} ({{ fic.format }}) + {% endif %} + Source + {% if fic.completed and escaped_url %} + Convert + {% endif %} +Your fic has finished processing and you can download it now:
-Download {{ fic.title }} - by {{ fic.author }} ({{ fic.format }})
- {% if escaped_url %} -Convert {{ fic.title }} to other formats
- {% endif %} - {% else %} - {% if fic.failure %} - Your fic failed to process. Please check the URL and the error message below.Not done yet. This page will periodically poll to see if your story has finished.
- {% endif %} - {% endif %} -Or see your personal list of previously downloaded fanfics.
-See your personal list of previously downloaded fanfics.
