make espri callbacks actualy work
[objavi2.git] / espri.cgi
blobe6891023462b2a305da324e44b3b538d36aa8c20
1 #!/usr/bin/python
3 # Part of the Objavi2 package. This script imports e-books into Booki
5 # Copyright (C) 2009 Douglas Bagnall
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 import os, sys
22 import re, time
23 from urllib2 import urlopen, HTTPError
24 from urlparse import urlsplit
25 from urllib import unquote
26 import traceback
28 from objavi import epub
29 from objavi.book_utils import log
30 from objavi.cgi_utils import output_blob_and_exit, parse_args, print_template_and_exit, output_blob_and_shut_up
31 from objavi.cgi_utils import is_name, is_utf8, is_url
32 from objavi import config
34 IA_EPUB_URL = "http://www.archive.org/download/%s/%s.epub"
36 def print_form_and_exit(booklink):
37 print_template_and_exit('templates/espri.html',
38 {'booklink': booklink, }
41 def async_start(content, mimetype):
42 """Begin (and in many cases, finish) http output.
43 In asynchronous modes, fork and close down stdout.
44 """
45 output_blob_and_shut_up(content, mimetype)
46 log(sys.stdout, sys.stderr, sys.stdin)
47 if os.fork():
48 os._exit(0)
49 sys.stdout.close()
50 sys.stdin.close()
51 #log(sys.stdout, sys.stderr, sys.stdin)
54 def async_callback(callback_url, **kwargs):
55 """Call the callback url with each message."""
56 pid = os.fork()
57 if pid:
58 log('child %s is doing callback with message %r' % (pid, kwargs, ))
59 return
60 from urllib2 import urlopen, URLError
61 from urllib import urlencode
62 data = urlencode(kwargs)
63 try:
64 f = urlopen(callback_url, data)
65 time.sleep(2)
66 f.close()
67 except URLError, e:
68 traceback.print_exc()
69 log("ERROR in callback:\n %r\n %s %s" % (e.url, e.code, e.msg))
70 os._exit(0)
73 def espri(epuburl, zipurl):
74 f = urlopen(epuburl)
75 s = f.read()
76 f.close()
77 e = epub.Epub()
78 e.load(s)
79 e.parse_meta()
80 e.parse_opf()
81 e.parse_ncx()
82 e.make_bookizip(zipurl)
84 def ia_espri(book_id):
85 epuburl = IA_EPUB_URL % (book_id, book_id)
86 log(epuburl)
87 zipurl = '%s/%s.zip' % (config.BOOKI_BOOK_DIR, book_id)
88 espri(epuburl, zipurl)
89 return zipurl
91 def inet_espri(epuburl):
92 filename = '_'.join(unquote(os.path.basename(urlsplit(epuburl).path)).split())
93 if filename.lower().endswith('.epub'):
94 filename = filename[:-5]
95 zipurl = '%s/%s-%s.zip' % (config.BOOKI_BOOK_DIR, filename, time.strftime('%F_%T'))
96 espri(epuburl, zipurl)
97 return zipurl
99 def wikibooks_espri(book_id):
100 epuburl = IA_EPUB_URL % (book_id, book_id)
101 log(epuburl)
102 zipurl = '%s/%s.zip' % (config.BOOKI_BOOK_DIR, book_id)
103 espri(epuburl, zipurl)
104 return zipurl
105 pass
108 SOURCES = {
109 'archive.org': {'function': ia_espri},
110 'url': {'function': inet_espri},
111 'wikibooks': {'function': wikibooks_espri},
113 ARG_VALIDATORS = {
114 "source": SOURCES.__contains__,
115 "book": is_utf8,
116 "url": is_url, #obsolete
117 'mode': ('zip', 'html', 'callback').__contains__,
118 'callback': is_url,
121 def ensure_backwards_compatibility(args):
122 """Mutate args to match previous API"""
123 if 'url' in args:
124 args['source'] = 'url'
125 args['book'] = args['url']
126 if 'source' not in args:
127 args['source'] = 'archive.org'
130 if __name__ == '__main__':
131 log('here')
132 args = parse_args(ARG_VALIDATORS)
133 ensure_backwards_compatibility(args)
134 mode = args.get('mode', 'html')
135 book = args.get('book')
136 source = args.get('source', 'archive.org')
137 source_fn = SOURCES.get(source)['function']
139 if mode == 'callback':
140 callback_url = args['callback']
141 async_start('OK, got it... will call %r when done' % (callback_url,),
142 'text/plain')
143 log('here')
144 url = None
145 if book is not None:
146 try:
147 url = source_fn(book)
148 book_link = '<p>Download <a href="%s">%s</a>.</p>' % (url, url)
149 except Exception, e:
150 traceback.print_exc()
151 log(e, args)
152 book_link = '<p>Error: <b>%s</b> when trying to get <b>%s</b></p>' % (e, book)
153 if mode != 'html':
154 raise
155 else:
156 book_link = ''
158 log('here')
159 if mode == 'callback':
160 async_callback(callback_url, url=url)
162 elif mode == 'zip' and url is not None:
163 f = open(url)
164 data = f.read()
165 f.close()
166 output_blob_and_exit(data, config.BOOKIZIP_MIMETYPE,
167 os.path.basename(url))
168 else:
169 log(book_link)
170 print_form_and_exit(book_link)
171 log('done!')