def GET(self, id_): self.login_required() try: id_ = int(id_) except: return "the id is invalid!<br />" bk = Book.get_by_id(id_) if not bk: return "the book(%d) not exist!<br />" % id_ bkcls = BookClass(bk.title) if not bkcls: return "the book(%d) not exist!<br />" % id_ #如果是漫画类,则不管是否选择了“单独推送”,都自动变成“单独推送” if issubclass(bkcls, BaseComicBook): separate = 'true' else: separate = web.input().get('separate', 'true') if main.session.username not in bk.users: bk.users.append(main.session.username) bk.separate = bool(separate in ('true', '1')) bk.put() raise web.seeother('/my')
def POST(self, mgrType): web.header('Content-Type', 'application/json') user = self.getcurrentuser() id_ = web.input().get('id_') try: id_ = int(id_) except: return json.dumps({'status': _('The id is invalid!')}) bk = Book.get_by_id(id_) if not bk: return json.dumps({'status': _('The book(%d) not exist!') % id_}) if mgrType.lower() == 'unsubscribe': if user.name in bk.users: bk.users.remove(user.name) bk.separate = False bk.put() #为安全起见,退订后也删除网站登陆信息(如果有的话) subs_info = user.subscription_info(bk.title) if subs_info: subs_info.delete() return json.dumps({ 'status': 'ok', 'title': bk.title, 'desc': bk.description }) elif mgrType.lower() == 'subscribe': separate = web.input().get('separate', '') respDict = {'status': 'ok'} bkcls = BookClass(bk.title) if not bkcls: return json.dumps({'status': 'The book(%d) not exist!' % id_}) #如果是漫画类,则不管是否选择了“单独推送”,都自动变成“单独推送” if issubclass(bkcls, BaseComicBook): separate = 'true' if user.name not in bk.users: bk.users.append(user.name) bk.separate = bool(separate.lower() in ('true', '1')) bk.put() respDict['title'] = bk.title respDict['desc'] = bk.description respDict['needs_subscription'] = bk.needs_subscription respDict['subscription_info'] = bool( user.subscription_info(bk.title)) respDict['separate'] = bk.separate return json.dumps(respDict) else: return json.dumps({'status': 'unknown command: %s' % mgrType})
def GET(self): username = web.input().get('u') id_ = web.input().get('id') #for debug self.queue2push = defaultdict(list) books = Book.all() if username: #现在投递【测试使用】,不需要判断时间和星期 sent = [] books2push = Book.get_by_id( int(id_)) if id_ and id_.isdigit() else None books2push = [books2push] if books2push else books for book in books2push: if not id_ and username not in book.users: continue user = KeUser.all().filter("name = ", username).get() if user and user.kindle_email: self.queueit(user, book.key().id(), book.separate) sent.append(book.title) self.flushqueue() if len(sent): tips = _("Book(s) (%s) put to queue!") % u', '.join(sent) else: tips = _("No book to deliver!") return self.render('autoback.html', "Delivering", tips=tips) #定时cron调用 sentcnt = 0 for book in books: if not book.users: #没有用户订阅此书 continue bkcls = None if book.builtin: bkcls = BookClass(book.title) if not bkcls: continue #确定此书是否需要下载 for u in book.users: user = KeUser.all().filter("enable_send = ", True).filter("name = ", u).get() if not user or not user.kindle_email: continue #先判断当天是否需要推送 day = local_time('%A', user.timezone) usrdays = user.send_days if bkcls and bkcls.deliver_days: #按星期推送 days = bkcls.deliver_days if not isinstance(days, list): days = [days] if day not in days: continue elif usrdays and day not in usrdays: #为空也表示每日推送 continue #时间判断 h = int(local_time("%H", user.timezone)) + 1 if h >= 24: h -= 24 if bkcls and bkcls.deliver_times: times = bkcls.deliver_times if not isinstance(times, list): times = [times] if h not in times: continue elif user.send_time != h: continue #到了这里才是需要推送的 self.queueit(user, book.key().id(), book.separate) sentcnt += 1 self.flushqueue() return "Put <strong>%d</strong> books to queue!" % sentcnt
def GET(self): bookid = web.input().get("id") emails = web.input().get("emails") booktype = web.input().get("type", "mobi") if not bookid or not emails: return "No book to send!<br />" try: bookid = int(bookid) except: return "id of book is invalid!<br />" bk = Book.get_by_id(bookid) if not bk: return "Title of feeds not exist!<br />" if bk.builtin: book = BookClass(bk.title) if not book: return "the builtin book not exist!<br />" book = book() else: # 自定义RSS if bk.feedscount == 0: return "the book has no feed!<br />" book = BaseFeedBook() book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed.title, feed.url, feed.isfulltext) for feed in feeds] book.url_filters = [flt.url for flt in UrlFilter.all()] emails = emails.split(',') opts = oeb = None # 创建 OEB global log opts = getOpts() oeb = CreateOeb(log, None, opts) setMetaData(oeb, book.title, book.language, local_time(), SrcEmail) oeb.container = ServerContainer(log) #guide mhfile = book.mastheadfile if mhfile: id, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id, href, MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) coverfile = book.coverfile if coverfile: id, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id) itemcnt = 0 sections = OrderedDict() # 对于html文件,变量名字自文档 # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容 for sec_or_media, url, title, content, brief in book.Items(): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r'image/'): id, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id, href, sec_or_media, data=content) else: id, href = oeb.manifest.generate(id='feed', href='feed%d.htm'%itemcnt) item = oeb.manifest.add(id, href, 'text/html', data=content) oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append((title, item, brief)) itemcnt += 1 if itemcnt > 0: # 建立TOC,杂志模式需要为两层目录结构 for sec in sections.keys(): sectoc = oeb.toc.add(sec, sections[sec][0][1].href) for title, a, brief in sections[sec]: sectoc.add(title, a.href, description=brief if brief else None) #TODO oeb.toc.rationalize_play_orders() oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, log) self.SendToKindle(emails, book.title, booktype, str(oIO.getvalue())) rs = "%s(%s).%s Sent!"%(book.title,local_time(),booktype) log.info(rs) return rs else: self.deliverlog(emails, book.title, 0, status='nonews') rs = "No new feeds." log.info(rs) return rs
def GET(self): username = web.input().get("u") bookid = web.input().get("id") to = web.input().get("to") booktype = web.input().get("type", "mobi") titlefmt = web.input().get("titlefmt") tz = int(web.input().get("tz", TIMEZONE)) if not bookid or not to: return "No book to send!<br />" try: bookid = int(bookid) except: return "id of book is invalid!<br />" bk = Book.get_by_id(bookid) if not bk: return "Title of feeds not exist!<br />" if bk.builtin: book = BookClass(bk.title) if not book: return "the builtin book not exist!<br />" book = book() book.url_filters = [flt.url for flt in UrlFilter.all()] else: # 自定义RSS if bk.feedscount == 0: return "the book has no feed!<br />" book = BaseFeedBook() book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed.title, feed.url, feed.isfulltext) for feed in feeds] book.url_filters = [flt.url for flt in UrlFilter.all()] opts = oeb = None # 创建 OEB global log opts = getOpts() oeb = CreateOeb(log, None, opts) title = "%s %s" % (book.title, local_time(titlefmt, tz)) if titlefmt else book.title setMetaData(oeb, title, book.language, local_time(tz=tz), SrcEmail) oeb.container = ServerContainer(log) # guide mhfile = book.mastheadfile if mhfile: id, href = oeb.manifest.generate("masthead", mhfile) # size:600*60 oeb.manifest.add(id, href, MimeFromFilename(mhfile)) oeb.guide.add("masthead", "Masthead Image", href) coverfile = book.coverfile if coverfile: id, href = oeb.manifest.generate("cover", coverfile) item = oeb.manifest.add(id, href, MimeFromFilename(coverfile)) oeb.guide.add("cover", "Cover", href) oeb.metadata.add("cover", id) itemcnt = 0 sections = OrderedDict() # 对于html文件,变量名字自文档 # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容 for sec_or_media, url, title, content, brief in book.Items(opts): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r"image/"): id, href = oeb.manifest.generate(id="img", href=title) item = oeb.manifest.add(id, href, sec_or_media, data=content) else: id, href = oeb.manifest.generate(id="feed", href="feed%d.html" % itemcnt) item = oeb.manifest.add(id, href, "application/xhtml+xml", data=content) oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append((title, item, brief)) itemcnt += 1 if itemcnt > 0: # 建立TOC,杂志模式需要为两层目录结构 stoc = ["<html><head><title>Table Of Contents</title></head><body>"] for sec in sections.keys(): stoc.append('<h3><a href="%s">%s</a></h3>' % (sections[sec][0][1].href, sec)) sectoc = oeb.toc.add(sec, sections[sec][0][1].href) for title, a, brief in sections[sec]: stoc.append(' <a href="%s">%s</a><br />' % (a.href, title)) sectoc.add(title, a.href, description=brief if brief else None) stoc.append("</body></html>") id, href = oeb.manifest.generate(id="toc", href="toc.html") item = oeb.manifest.add(id, href, "application/xhtml+xml", data="".join(stoc)) oeb.guide.add("toc", "Table of Contents", href) oeb.spine.add(item, True) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, log) self.SendToKindle(username, to, book.title, booktype, str(oIO.getvalue()), tz) rs = "%s(%s).%s Sent!" % (book.title, local_time(tz=tz), booktype) log.info(rs) return rs else: self.deliverlog(username, to, book.title, 0, status="nonews", tz=tz) rs = "No new feeds." log.info(rs) return rs
def GET(self): username = web.input().get("u") bookid = web.input().get("id") #to = web.input().get("to") #booktype = web.input().get("type", "mobi") #titlefmt = web.input().get("titlefmt") #tz = int(web.input().get("tz", TIMEZONE)) #if not bookid: # return "No book to send!<br />" user = KeUser.all().filter("name = ", username).get() if not user: return "User not exist!<br />" to = user.kindle_email booktype = user.book_type titlefmt = user.titlefmt tz = user.timezone bookid = bookid.split(',') if ',' in bookid else [bookid] bks = [] for id in bookid: try: bks.append(Book.get_by_id(int(id))) except: continue #return "id of book is invalid or book not exist!<br />" if len(bks) == 0: return "No have book to push!" elif len(bks) == 1: book4meta = BookClass(bks[0].title) if bks[0].builtin else bks[0] else: #多本书合并推送时使用“自定义RSS”的元属性 book4meta = user.ownfeeds if not book4meta: return "No have book to push.<br />" opts = oeb = None # 创建 OEB global log opts = getOpts() oeb = CreateOeb(log, None, opts) title = "%s %s" % (book4meta.title, local_time(titlefmt, tz)) if titlefmt else book4meta.title setMetaData(oeb, title, book4meta.language, local_time(tz=tz), 'KindleEar') oeb.container = ServerContainer(log) #guide if len(bks)==1 and bks[0].builtin: mhfile = book4meta.mastheadfile coverfile = book4meta.coverfile else: mhfile = DEFAULT_MASTHEAD coverfile = DEFAULT_COVER if mhfile: id, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id, href, MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) if coverfile: id, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id) itemcnt,imgindex = 0,0 sections = OrderedDict() for bk in bks: if bk.builtin: book = BookClass(bk.title) if not book: log.warn('not exist book <%s>' % bk.title) continue book = book(imgindex=imgindex) book.url_filters = [flt.url for flt in user.urlfilter] else: # 自定义RSS if bk.feedscount == 0: continue #return "the book has no feed!<br />" book = BaseFeedBook(imgindex=imgindex) book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed.title, feed.url, feed.isfulltext) for feed in feeds] book.url_filters = [flt.url for flt in user.urlfilter] # 对于html文件,变量名字自文档 # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容 for sec_or_media, url, title, content, brief in book.Items(opts,user): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r'image/'): id, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id, href, sec_or_media, data=content) imgindex += 1 else: id, href = oeb.manifest.generate(id='feed', href='feed%d.html'%itemcnt) item = oeb.manifest.add(id, href, 'application/xhtml+xml', data=content) oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append((title, item, brief)) itemcnt += 1 if itemcnt > 0: # 建立TOC,杂志模式需要为两层目录结构 stoc = ['<html><head><title>Table Of Contents</title></head><body><h2>Table Of Contents</h2>'] for sec in sections.keys(): stoc.append('<h3><a href="%s">%s</a></h3>'%(sections[sec][0][1].href,sec)) sectoc = oeb.toc.add(sec, sections[sec][0][1].href) for title, a, brief in sections[sec]: stoc.append(' <a href="%s">%s</a><br />'%(a.href,title)) sectoc.add(title, a.href, description=brief if brief else None) stoc.append('</body></html>') id, href = oeb.manifest.generate(id='toc', href='toc.html') item = oeb.manifest.add(id, href, 'application/xhtml+xml', data=''.join(stoc)) oeb.guide.add('toc', 'Table of Contents', href) oeb.spine.add(item, True) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, log) self.SendToKindle(username, to, book4meta.title, booktype, str(oIO.getvalue()), tz) rs = "%s(%s).%s Sent!"%(book4meta.title, local_time(tz=tz), booktype) log.info(rs) return rs else: self.deliverlog(username, to, book4meta.title, 0, status='nonews',tz=tz) rs = "No new feeds." log.info(rs) return rs
def GET(self): username = web.input().get("u") bookid = web.input().get("id") user = KeUser.all().filter("name = ", username).get() if not user: return "User not exist!<br />" to = user.kindle_email if (';' in to) or (',' in to): to = to.replace(',', ';').replace(' ', '').split(';') booktype = user.book_type #mobi,epub bookmode = user.book_mode or 'periodical' #periodical,comic titlefmt = user.titlefmt tz = user.timezone bookid = bookid.split(',') if ',' in bookid else [bookid] bks = [] for id_ in bookid: try: bks.append(Book.get_by_id(int(id_))) except: continue #return "id of book is invalid or book not exist!<br />" book4meta = None if len(bks) == 0: return "No have book to push!" elif len(bks) == 1: if bks[0].builtin: book4meta = BookClass(bks[0].title) mhfile = book4meta.mastheadfile coverfile = book4meta.coverfile if issubclass(book4meta, BaseComicBook ): #如果单独推送一个继承自BaseComicBook的书籍,则自动设置为漫画模式 bookmode = 'comic' else: #单独的推送自定义RSS book4meta = bks[0] mhfile = DEFAULT_MASTHEAD coverfile = DEFAULT_COVER else: #多本书合并推送时使用“自定义RSS”的元属性 book4meta = user.ownfeeds mhfile = DEFAULT_MASTHEAD coverfile = DEFAULT_COVER_BV if user.merge_books else DEFAULT_COVER if not book4meta: return "No have book to push.<br />" opts = None oeb = None # 创建 OEB #global log opts = getOpts(user.device, bookmode) oeb = CreateOeb(main.log, None, opts) bookTitle = "%s %s" % (book4meta.title, local_time( titlefmt, tz)) if titlefmt else book4meta.title if bookmode == 'comic': pubtype = 'book:book:KindleEar' else: pubtype = 'periodical:magazine:KindleEar' setMetaData(oeb, bookTitle, book4meta.language, local_time("%Y-%m-%d", tz), pubtype=pubtype) oeb.container = ServerContainer(main.log) #guide if mhfile: id_, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id_, href, MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) if coverfile: imgData = None imgMime = '' #使用保存在数据库的用户上传的封面 if coverfile == DEFAULT_COVER and user.cover: imgData = user.cover imgMime = 'image/jpeg' #保存在数据库中的只可能是jpeg格式 elif callable(coverfile): #如果封面需要回调的话 try: imgData = book4meta().coverfile() if imgData: imgType = imghdr.what(None, imgData) if imgType: #如果是合法图片 imgMime = r"image/" + imgType else: main.log.warn( 'content of cover is invalid : [%s].' % bookTitle) imgData = None except Exception as e: main.log.warn( 'Failed to fetch cover for book [%s]. [Error: %s]' % (bookTitle, str(e))) coverfile = DEFAULT_COVER imgData = None imgMime = '' if imgData and imgMime: id_, href = oeb.manifest.generate('cover', 'cover.jpg') item = oeb.manifest.add(id_, href, imgMime, data=imgData) else: id_, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id_, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) elif len(bks) > 1 and DEFAULT_COVER: #将所有书籍的封面拼贴成一个 #如果DEFAULT_COVER=None说明用户不需要封面 id_, href = oeb.manifest.generate('cover', 'cover.jpg') item = oeb.manifest.add(id_, href, 'image/jpeg', data=self.MergeCovers(bks, opts, user)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt, imgindex = 0, 0 sections = OrderedDict() toc_thumbnails = {} #map img-url -> manifest-href for bk in bks: if bk.builtin: cbook = BookClass(bk.title) if not cbook: main.log.warn('not exist book <%s>' % bk.title) continue book = cbook(imgindex=imgindex, opts=opts, user=user) book.url_filters = [flt.url for flt in user.urlfilter] if bk.needs_subscription: #需要登录 subs_info = user.subscription_info(bk.title) if subs_info: book.account = subs_info.account book.password = subs_info.password else: # 自定义RSS if bk.feedscount == 0: continue #return "the book has no feed!<br />" book = BaseFeedBook(imgindex=imgindex, opts=opts, user=user) book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [] for feed in feeds: if feed.url.startswith( ("http://www.cartoonmad.com", "http://ac.qq.com", "http://m.ac.qq.com")): self.ProcessComicRSS(username, user, feed) else: book.feeds.append( (feed.title, feed.url, feed.isfulltext)) book.url_filters = [flt.url for flt in user.urlfilter] # 对于html文件,变量名字自文档,thumbnail为文章第一个img的url # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容, # img的thumbail仅当其为article的第一个img为True try: #书的质量可能不一,一本书的异常不能影响其他书籍的推送 for sec_or_media, url, title, content, brief, thumbnail in book.Items( ): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r'image/'): id_, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id_, href, sec_or_media, data=content) if thumbnail: toc_thumbnails[url] = href imgindex += 1 else: #id, href = oeb.manifest.generate(id='feed', href='feed%d.html'%itemcnt) #item = oeb.manifest.add(id, href, 'application/xhtml+xml', data=content) #oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append( (title, brief, thumbnail, content)) itemcnt += 1 except Exception as e: excFileName, excFuncName, excLineNo = get_exc_location() main.log.warn( "Failed to push <%s> : %s, in file '%s', %s (line %d)" % (book.title, str(e), excFileName, excFuncName, excLineNo)) continue volumeTitle = '' if itemcnt > 0: #漫画模式不需要TOC和缩略图 if bookmode == 'comic': insertHtmlToc = False insertThumbnail = False if len(bks) == 1 and book: #因为漫画模式没有目录,所以在标题中添加卷号 volumeTitle = book.LastDeliveredVolume() oeb.metadata.clear('title') oeb.metadata.add('title', bookTitle + volumeTitle) else: insertHtmlToc = GENERATE_HTML_TOC insertThumbnail = GENERATE_TOC_THUMBNAIL InsertToc(oeb, sections, toc_thumbnails, insertHtmlToc, insertThumbnail) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, main.log) try: ultima_log = DeliverLog.all().order('-time').get() except: ultima_log = sorted(DeliverLog.all(), key=attrgetter('time'), reverse=True) ultima_log = ultima_log[0] if ultima_log else None if ultima_log: diff = datetime.datetime.utcnow() - ultima_log.datetime if diff.days * 86400 + diff.seconds < 10: time.sleep(8) self.SendToKindle(username, to, book4meta.title + volumeTitle, booktype, str(oIO.getvalue()), tz) rs = "%s(%s).%s Sent!" % (book4meta.title, local_time(tz=tz), booktype) main.log.info(rs) return rs else: self.deliverlog(username, str(to), book4meta.title + volumeTitle, 0, status='nonews', tz=tz) rs = "No new feeds." main.log.info(rs) return rs
def MergeCovers(self, bks, opts, user): coverfiles = [] callableInstances = [] for bk in bks: if bk.builtin: book = BookClass(bk.title) if book and book.coverfile: if callable(book.coverfile): instan = book() callableInstances.append(instan) coverfiles.append(instan.coverfile) else: coverfiles.append(book.coverfile) elif DEFAULT_COVER: coverfiles.append(DEFAULT_COVER) num_imgs = len(coverfiles) if num_imgs > 9: #大于9个则随机选择9个 coverfiles = random.sample(coverfiles, 9) num_imgs = 9 imgs_orig = [] srvcontainer = ServerContainer() for cv in coverfiles: img = None #使用用户上传的保存在数据库的封面 if cv == DEFAULT_COVER and user.cover: try: img = Image.open(StringIO.StringIO(user.cover)) except: img = None elif callable(cv): #如果封面需要回调的话 try: data = cv() if data: img = Image.open(StringIO.StringIO(data)) else: cv = DEFAULT_COVER img = None except Exception as e: main.log.warn( '[MergeCovers] Content of cover is invalid : [%s].' % str(e)) cv = DEFAULT_COVER img = None try: if not img: img = Image.open(StringIO.StringIO(srvcontainer.read(cv))) except Exception as e: main.log.warn('[MergeCovers] Cover file invalid [%s], %s' % (str(cv), str(e))) else: imgs_orig.append(img) num_imgs = len(imgs_orig) if num_imgs == 0: return srvcontainer.read(DEFAULT_COVER) #所有图像的宽高最大值,保证粘贴过程不丢失任何像素 w = max([im.size[0] for im in imgs_orig]) h = max([im.size[1] for im in imgs_orig]) if num_imgs == 1: pos_info = [(0, 0)] new_size = (w, h) elif num_imgs <= 4: #4等分 pos_info = [(0, 0), (w, 0), (0, h), (w, h)] new_size = (w * 2, h * 2) if num_imgs < 4: #填满4格 imgs_orig += random.sample(imgs_orig, 4 - num_imgs) elif num_imgs in (5, 6): #1个大的,5个小的 pos_info = [[(0, 0, w * 2, h * 2), (w * 2, 0), (w * 2, h), (0, h * 2), (w, h * 2), (w * 2, h * 2)], [(w, 0, w * 2, h * 2), (0, 0), (0, h), (0, h * 2), (w, h * 2), (w * 2, h * 2)], [(0, h, w * 2, h * 2), (0, 0), (w, 0), (w * 2, 0), (w * 2, h), (w * 2, h * 2)], [(0, 0), (w, 0), (w * 2, 0), (0, h), (w, h, w * 2, h * 2), (0, h * 2)]] pos_info = random.choice(pos_info) if num_imgs == 5: #填满6格 #pos_info = [pos_info[0]] + random.sample(pos_info[1:], 4) imgs_orig.append(random.choice(imgs_orig)) new_size = (w * 3, h * 3) else: #九宫格 pos_info = [(0, 0), (w, 0), (w * 2, 0), (0, h), (w, h), (w * 2, h), (0, h * 2), (w, h * 2), (w * 2, h * 2)] new_size = (w * 3, h * 3) if num_imgs < 9: imgs_orig += random.sample(imgs_orig, 9 - num_imgs) #随机安排每个图片的位置 random.shuffle(pos_info) #拼接图片 imgnew = Image.new('L' if opts.graying_image else 'RGB', new_size, 'white') for idx, img in enumerate(imgs_orig): pos = pos_info[idx] if len(pos) > 2: #如果元素为4个,则前两个是在大图中的位置,后两个是缩小后的图片尺寸 img = img.resize(pos[2:]) pos = pos[:2] imgnew.paste(img, pos) #新生成的图片再整体缩小到设定大小 rw, rh = opts.reduce_image_to ratio = min( float(rw) / float(new_size[0]), float(rh) / float(new_size[1])) imgnew = imgnew.resize( (int(new_size[0] * ratio), int(new_size[1] * ratio))) data = StringIO.StringIO() imgnew.save(data, 'JPEG') return data.getvalue()
def GET(self): username = web.input().get("u") bookid = web.input().get("id") user = KeUser.all().filter("name = ", username).get() if not user: return "User not exist!<br />" to = user.kindle_email booktype = user.book_type titlefmt = user.titlefmt tz = user.timezone bookid = bookid.split(',') if ',' in bookid else [bookid] bks = [] for id_ in bookid: try: bks.append(Book.get_by_id(int(id_))) except: continue #return "id of book is invalid or book not exist!<br />" if len(bks) == 0: return "No have book to push!" elif len(bks) == 1: book4meta = BookClass(bks[0].title) if bks[0].builtin else bks[0] else: #多本书合并推送时使用“自定义RSS”的元属性 book4meta = user.ownfeeds if not book4meta: return "No have book to push.<br />" opts = oeb = None # 创建 OEB #global log opts = getOpts(user.device) oeb = CreateOeb(main.log, None, opts) title = "%s %s" % (book4meta.title, local_time(titlefmt, tz)) if titlefmt else book4meta.title setMetaData(oeb, title, book4meta.language, local_time("%Y-%m-%d",tz), 'KindleEar') oeb.container = ServerContainer(main.log) #guide if len(bks) == 1: if bks[0].builtin: mhfile = book4meta.mastheadfile coverfile = book4meta.coverfile else: #单独的推送自定义RSS mhfile = DEFAULT_MASTHEAD coverfile = DEFAULT_COVER else: mhfile = DEFAULT_MASTHEAD coverfile = DEFAULT_COVER_BV if user.merge_books else DEFAULT_COVER if mhfile: id_, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id_, href, MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) if coverfile: id_, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id_, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) elif len(bks) > 1 and DEFAULT_COVER: #将所有书籍的封面拼贴成一个 #如果DEFAULT_COVER=None说明用户不需要封面 id_, href = oeb.manifest.generate('cover', 'cover.jpg') item = oeb.manifest.add(id_, href, 'image/jpeg', data=self.MergeCovers(bks, opts)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt,imgindex = 0,0 sections = OrderedDict() toc_thumbnails = {} #map img-url -> manifest-href for bk in bks: if bk.builtin: book = BookClass(bk.title) if not book: main.log.warn('not exist book <%s>' % bk.title) continue book = book(imgindex=imgindex) book.url_filters = [flt.url for flt in user.urlfilter] if bk.needs_subscription: #需要登录 subs_info = user.subscription_info(bk.title) if subs_info: book.account = subs_info.account book.password = subs_info.password else: # 自定义RSS if bk.feedscount == 0: continue #return "the book has no feed!<br />" book = BaseFeedBook(imgindex=imgindex) book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed.title, feed.url, feed.isfulltext) for feed in feeds] book.url_filters = [flt.url for flt in user.urlfilter] # 对于html文件,变量名字自文档,thumbnail为文章第一个img的url # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容, # img的thumbail仅当其为article的第一个img为True try: #书的质量可能不一,一本书的异常不能影响推送 for sec_or_media, url, title, content, brief, thumbnail in book.Items(opts,user): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r'image/'): id_, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id_, href, sec_or_media, data=content) if thumbnail: toc_thumbnails[url] = href imgindex += 1 else: #id, href = oeb.manifest.generate(id='feed', href='feed%d.html'%itemcnt) #item = oeb.manifest.add(id, href, 'application/xhtml+xml', data=content) #oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append((title, brief, thumbnail, content)) itemcnt += 1 except Exception as e: main.log.warn("Failure in pushing book '%s' : %s" % (book.title, str(e))) continue if itemcnt > 0: InsertToc(oeb, sections, toc_thumbnails) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, main.log) ultima_log = DeliverLog.all().order('-time').get() if ultima_log: diff = datetime.datetime.utcnow() - ultima_log.datetime if diff.days * 86400 + diff.seconds < 5: time.sleep(8) self.SendToKindle(username, to, book4meta.title, booktype, str(oIO.getvalue()), tz) rs = "%s(%s).%s Sent!"%(book4meta.title, local_time(tz=tz), booktype) main.log.info(rs) return rs else: self.deliverlog(username, to, book4meta.title, 0, status='nonews',tz=tz) rs = "No new feeds." main.log.info(rs) return rs
def GET(self): username = web.input().get("u") bookid = web.input().get("id") user = KeUser.all().filter("name = ", username).get() if not user: return "User not exist!<br />" to = user.kindle_email booktype = user.book_type titlefmt = user.titlefmt tz = user.timezone bookid = bookid.split(',') if ',' in bookid else [bookid] bks = [] for id in bookid: try: bks.append(Book.get_by_id(int(id))) except: continue #return "id of book is invalid or book not exist!<br />" if len(bks) == 0: return "No have book to push!" elif len(bks) == 1: book4meta = BookClass(bks[0].title) if bks[0].builtin else bks[0] else: #多本书合并推送时使用“自定义RSS”的元属性 book4meta = user.ownfeeds if not book4meta: return "No have book to push.<br />" opts = oeb = None # 创建 OEB #global log opts = getOpts(user.device) oeb = CreateOeb(main.log, None, opts) title = "%s %s" % (book4meta.title, local_time(titlefmt, tz)) if titlefmt else book4meta.title setMetaData(oeb, title, book4meta.language, local_time("%Y-%m-%d",tz), 'KindleEar') oeb.container = ServerContainer(main.log) #guide if len(bks)==1 and bks[0].builtin: mhfile = book4meta.mastheadfile coverfile = book4meta.coverfile else: mhfile = DEFAULT_MASTHEAD coverfile = DEFAULT_COVER_BV if user.merge_books else DEFAULT_COVER if mhfile: id_, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id_, href, MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) if coverfile: id_, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id_, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) elif len(bks)>1 and DEFAULT_COVER: #将所有书籍的封面拼贴成一个 #如果DEFAULT_COVER=None说明用户不需要封面 id_, href = oeb.manifest.generate('cover', 'cover.jpg') item = oeb.manifest.add(id_, href, 'image/jpeg', data=self.MergeCovers(bks,opts)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt,imgindex = 0,0 sections = OrderedDict() toc_thumbnails = {} #map img-url -> manifest-href for bk in bks: if bk.builtin: book = BookClass(bk.title) if not book: main.log.warn('not exist book <%s>' % bk.title) continue book = book(imgindex=imgindex) book.url_filters = [flt.url for flt in user.urlfilter] if bk.needs_subscription: #需要登录 subs_info = user.subscription_info(bk.title) if subs_info: book.account = subs_info.account book.password = subs_info.password else: # 自定义RSS if bk.feedscount == 0: continue #return "the book has no feed!<br />" book = BaseFeedBook(imgindex=imgindex) book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed.title, feed.url, feed.isfulltext) for feed in feeds] book.url_filters = [flt.url for flt in user.urlfilter] # 对于html文件,变量名字自文档,thumbnail为文章第一个img的url # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容, # img的thumbail仅当其为article的第一个img为True for sec_or_media, url, title, content, brief, thumbnail in book.Items(opts,user): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r'image/'): id_, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id_, href, sec_or_media, data=content) if thumbnail: toc_thumbnails[url] = href imgindex += 1 else: #id, href = oeb.manifest.generate(id='feed', href='feed%d.html'%itemcnt) #item = oeb.manifest.add(id, href, 'application/xhtml+xml', data=content) #oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append((title, brief, thumbnail, content)) itemcnt += 1 if itemcnt > 0: InsertToc(oeb, sections, toc_thumbnails) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, main.log) ultima_log = DeliverLog.all().order('-time').get() if ultima_log: diff = datetime.datetime.utcnow() - ultima_log.datetime if diff.days * 86400 + diff.seconds < 5: time.sleep(8) self.SendToKindle(username, to, book4meta.title, booktype, str(oIO.getvalue()), tz) rs = "%s(%s).%s Sent!"%(book4meta.title, local_time(tz=tz), booktype) main.log.info(rs) return rs else: self.deliverlog(username, to, book4meta.title, 0, status='nonews',tz=tz) rs = "No new feeds." main.log.info(rs) return rs
def MergeCovers(self, bks, opts): "将所有书籍的封面拼起来,为了更好的效果,请保证图片的大小统一。" from StringIO import StringIO from PIL import Image import random coverfiles = [] for bk in bks: if bk.builtin: book = BookClass(bk.title) if book and book.coverfile: coverfiles.append(book.coverfile) num_imgs = len(coverfiles) if num_imgs > 9:#大于9个则随机选择9个 coverfiles = random.sample(coverfiles, 9) num_imgs = 9 imgs_orig = [] srvcontainer = ServerContainer() for cv in coverfiles: try: img = Image.open(StringIO(srvcontainer.read(cv))) except Exception as e: continue else: imgs_orig.append(img) num_imgs = len(imgs_orig) if num_imgs == 0: return srvcontainer.read(DEFAULT_COVER) #所有图像的宽高最大值,保证粘贴过程不丢失任何像素 w = max([im.size[0] for im in imgs_orig]) h = max([im.size[1] for im in imgs_orig]) if num_imgs == 1: pos_info = [(0,0)] new_size = (w,h) elif num_imgs <=4: pos_info = [(0,0),(w,0),(0,h),(w,h)] new_size = (w*2,h*2) elif num_imgs in (5,6): #1个大的,4个或5个小的 pos_info = [[(0,0,w*2,h*2),(w*2,0),(w*2,h),(0,h*2),(w,h*2),(w*2,h*2)], [(w,0,w*2,h*2),(0,0),(0,h),(0,h*2),(w,h*2),(w*2,h*2)], [(0,h,w*2,h*2),(0,0),(w,0),(w*2,0),(w*2,h),(w*2,h*2)], [(0,0),(w,0),(w*2,0),(0,h),(w,h,w*2,h*2),(0,h*2)]] pos_info = random.choice(pos_info) if num_imgs == 5: pos_info = [pos_info[0]] + random.sample(pos_info[1:],4) new_size = (w*3,h*3) else: pos_info = [(0,0),(w,0),(w*2,0),(0,h),(w,h),(w*2,h),(0,h*2),(w,h*2),(w*2,h*2)] new_size = (w*3,h*3) #随机安排每个图片的位置 random.shuffle(pos_info) imgnew = Image.new('L' if opts.graying_image else 'RGB', new_size, 'white') for idx,img in enumerate(imgs_orig): pos = pos_info[idx] if len(pos) > 2: img = img.resize(pos[2:]) pos = pos[:2] imgnew.paste(img, pos) rw,rh = opts.reduce_image_to ratio = min(float(rw)/float(new_size[0]), float(rh)/float(new_size[0])) imgnew = imgnew.resize((int(new_size[0]*ratio), int(new_size[1]*ratio))) data = StringIO() imgnew.save(data, 'JPEG') return data.getvalue()
def GET(self): username = web.input().get("u") bookid = web.input().get("id") to = web.input().get("to") booktype = web.input().get("type", "mobi") titlefmt = web.input().get("titlefmt") tz = int(web.input().get("tz", TIMEZONE)) if not bookid or not to: return "No book to send!<br />" try: bookid = int(bookid) except: return "id of book is invalid!<br />" bk = Book.get_by_id(bookid) if not bk: return "Title of feeds not exist!<br />" if bk.builtin: book = BookClass(bk.title) if not book: return "the builtin book not exist!<br />" book = book() else: # 自定义RSS if bk.feedscount == 0: return "the book has no feed!<br />" book = BaseFeedBook() book.title = bk.title book.description = bk.description book.language = bk.language book.keep_image = bk.keep_image book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed.title, feed.url, feed.isfulltext) for feed in feeds] book.url_filters = [flt.url for flt in UrlFilter.all()] opts = oeb = None # 创建 OEB global log opts = getOpts() oeb = CreateOeb(log, None, opts) if titlefmt: title = "%s %s" % (book.title, local_time(titlefmt, tz)) else: title = book.title setMetaData(oeb, title, book.language, local_time(tz=tz), SrcEmail) oeb.container = ServerContainer(log) #guide mhfile = book.mastheadfile if mhfile: id, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id, href, MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) coverfile = book.coverfile if coverfile: id, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id) itemcnt = 0 sections = OrderedDict() # 对于html文件,变量名字自文档 # 对于图片文件,section为图片mime,url为原始链接,title为文件名,content为二进制内容 for sec_or_media, url, title, content, brief in book.Items(): if not sec_or_media or not title or not content: continue if sec_or_media.startswith(r'image/'): id, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id, href, sec_or_media, data=content) else: id, href = oeb.manifest.generate(id='feed', href='feed%d.htm'%itemcnt) item = oeb.manifest.add(id, href, 'text/html', data=content) oeb.spine.add(item, True) sections.setdefault(sec_or_media, []) sections[sec_or_media].append((title, item, brief)) itemcnt += 1 if itemcnt > 0: # 建立TOC,杂志模式需要为两层目录结构 for sec in sections.keys(): sectoc = oeb.toc.add(sec, sections[sec][0][1].href) for title, a, brief in sections[sec]: sectoc.add(title, a.href, description=brief if brief else None) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, log) self.SendToKindle(username, to, book.title, booktype, str(oIO.getvalue()), tz) rs = "%s(%s).%s Sent!"%(book.title, local_time(tz=tz), booktype) log.info(rs) return rs else: self.deliverlog(username, to, book.title, 0, status='nonews',tz=tz) rs = "No new feeds." log.info(rs) return rs
def GET(self): username = web.input().get('u') books = Book.all() if username: # 现在投递,不判断时间和星期 sent = [] for book in books: if username not in book.users: continue user = KeUser.all().filter("name = ", username).get() if user and user.kindle_email: self.queueit(user, book.key().id()) sent.append(book.title) if len(sent): tips = _("Book(s) (%s) put to queue!") % u', '.join(sent) else: tips = _("No book(s) to deliver!") return jjenv.get_template("autoback.html").render(nickname=session.username, title='Delivering',tips=tips) #定时cron调用 sentcnt = 0 for book in books: if not book.users: # 没有用户订阅此书 continue #确定此书是否需要下载 for u in book.users: user = KeUser.all().filter("enable_send = ",True).filter("name = ", u).get() if not user or not user.kindle_email: continue #先判断当天是否需要推送 day = local_time('%A', user.timezone) usrdays = user.send_days if usrdays and day not in usrdays: #为空也表示每日推送 continue #时间判断 h = int(local_time("%H", user.timezone)) + 1 h = h - 24 if h > 24 else h if user.send_time != h: continue #到了这里才算需要推送 if book.builtin: bkcls = BookClass(book.title) if not bkcls: continue if bkcls.deliver_days: #按星期推送 days = bkcls.deliver_days if not isinstance(days, list): days = [days] if day in days: self.queueit(user, book.key().id()) sentcnt += 1 else: #每天推送 self.queueit(user, book.key().id()) sentcnt += 1 else: self.queueit(user, book.key().id()) sentcnt += 1 return "Put <strong>%d</strong> books to queue!" % sentcnt
def GET(self): username = web.input().get('u') id_ = web.input().get('id') feedsId = web.input().get('feedsId') if id_: id_ = [int(item) for item in id_.split('|') if item.isdigit()] self.queue2push = defaultdict(list) books = Book.all() if username: #现在投递【测试使用】,不需要判断时间和星期 user = KeUser.all().filter("name = ", username).get() if not user or not user.kindle_email: return self.render('autoback.html', "Delivering", tips=_('The username not exist or the email of kindle is empty.')) sent = [] if id_: #推送特定账号指定的书籍,这里不判断特定账号是否已经订阅了指定的书籍,只要提供就推送 books2push = [Book.get_by_id(item) for item in id_ if Book.get_by_id(item)] else: #推送特定账号所有的书籍 books2push = [item for item in books if username in item.users] for book in books2push: self.queueit(user, book.key().id(), book.separate, feedsId) sent.append(book.title) self.flushqueue() if len(sent): tips = _("Book(s) (%s) put to queue!") % u', '.join(sent) else: tips = _("No book to deliver!") return self.render('autoback.html', "Delivering", tips=tips) #定时cron调用 sentcnt = 0 for book in books: if not book.users: #没有用户订阅此书 continue bkcls = None if book.builtin: bkcls = BookClass(book.title) if not bkcls: continue #确定此书是否需要下载 for u in book.users: user = KeUser.all().filter("enable_send = ",True).filter("name = ", u).get() if not user or not user.kindle_email: continue #先判断当天是否需要推送 day = local_time('%A', user.timezone) usrdays = user.send_days if bkcls and bkcls.deliver_days: #按星期推送 days = bkcls.deliver_days if not isinstance(days, list): days = [days] if day not in days: continue elif usrdays and day not in usrdays: #为空也表示每日推送 continue #时间判断 h = int(local_time("%H", user.timezone)) + 1 if h >= 24: h -= 24 if bkcls and bkcls.deliver_times: times = bkcls.deliver_times if not isinstance(times, list): times = [times] if h not in times: continue elif user.send_time != h: continue #到了这里才是需要推送的 self.queueit(user, book.key().id(), book.separate) sentcnt += 1 self.flushqueue() return "Put <strong>%d</strong> books to queue!" % sentcnt
def GET(self): id = web.input().get("id") emails = web.input().get("emails") booktype = web.input().get("type", "mobi") if not id or not emails: return "No book to send!<br />" try: id = int(id) except: return "id of book is invalid!<br />" bk = Book.all().ancestor(db.Key.from_path("Book", id)).get() if not bk: return "Title of feeds not exist!<br />" if bk.builtin: book = BookClass(bk.title) if not book: return "the builtin book not exist!<br />" book = book() else: # 自定义RSS feeds = bk.feeds() if feeds.count() == 0: return "the book has no feed!<br />" book = BaseFeedBook() book.title = bk.title book.description = bk.description book.language = bk.language book.feed_encoding = bk.feed_encoding book.page_encoding = bk.page_encoding book.mastheadfile = bk.mastheadfile book.coverfile = bk.coverfile book.keep_image = bk.keep_image book.fulltext_by_readability = True for feed in feeds: book.feeds.append((feed.title, feed.url)) emails = emails.split(',') opts = oeb = None # 创建 OEB global log opts = getOpts() oeb = CreateOeb(log, None, opts) setMetaData(oeb, book.title, book.language, local_time(), SrcEmail) oeb.container = ServerContainer(log) #guide mhfile = book.mastheadfile if book.mastheadfile else 'mh_default.gif' id, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id, href, 'image/gif') oeb.guide.add('masthead', 'Masthead Image', href) coverfile = book.coverfile if book.coverfile else DEFAULT_COVER if coverfile: id, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id, href, MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id) pages, idx = [], 0 sections = OrderedDict() # 对于html文件,变量名字自文档 # 对于图片文件,catalog为图片mime,url为原始链接,title为文件名,content为二进制内容 for section, url, title, content in book.Items(): if section.startswith(r'image/'): id, href = oeb.manifest.generate(id='img', href=title) item = oeb.manifest.add(id, href, section, data=content) else: id, href = oeb.manifest.generate(id='feed', href='feed%d.htm'%idx) item = oeb.manifest.add(id, href, 'text/html', data=content) oeb.spine.add(item, True) sections.setdefault(section, []).append((title, item)) idx += 1 if idx > 0: # 建立TOC,杂志模式需要为两层目录结构 for sec in sections.keys(): sectoc = oeb.toc.add(sec, sections[sec][0][1].href) for title, a in sections[sec]: sectoc.add(title, a.href) oIO = byteStringIO() o = EPUBOutput() if booktype == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, log) self.SendToKindle(emails, book.title, booktype, str(oIO.getvalue())) return "%s(%s).%s Sent!<br />"%(book.title,local_time(),booktype) else: return "No new feeds.<br />"