class Ebook: def __init__(self, ebook_name): self.opts = getOpts() self.oeb = CreateOeb(log, None, self.opts) self.ebook_name = ebook_name # 防止发出无内容的空书 self.has_content = False setMetaData(self.oeb, title=ebook_name) GENERATE_HTML_TOC = True GENERATE_TOC_THUMBNAIL = True self.insertHtmlToc = GENERATE_HTML_TOC self.insertThumbnail = GENERATE_TOC_THUMBNAIL self.sections = OrderedDict() self.book = MOBIOutput() def as_epub(self): self.book = EPUBOutput() return self def as_mobi(self): self.book = MOBIOutput() return self def add_section(self, book_name, chapter, content): self.sections.setdefault(book_name, []) self.sections[book_name].append((chapter, "b", "c", "<body>" + content + "</body>")) return self def add_sections(self, bookname, sections): if not sections: return try: for title, content in sections: self.add_section(bookname, title, content) except Exception as e: print(e) self.has_content = True def get_byte_book(self): if not self.has_content: return None toc_thumbnails = {"c": "https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"} InsertToc(self.oeb, self.sections, toc_thumbnails, self.insertHtmlToc, self.insertThumbnail) byte_book = byteStringIO() self.book.convert(self.oeb, byte_book, self.opts, log) return byte_book.getvalue()
def __init__(self, ebook_name): self.opts = getOpts() self.oeb = CreateOeb(log, None, self.opts) self.ebook_name = ebook_name # 防止发出无内容的空书 self.has_content = False setMetaData(self.oeb, title=ebook_name) GENERATE_HTML_TOC = True GENERATE_TOC_THUMBNAIL = True self.insertHtmlToc = GENERATE_HTML_TOC self.insertThumbnail = GENERATE_TOC_THUMBNAIL self.sections = OrderedDict() self.book = MOBIOutput()
def make(self): self._oeb = self._create_oeb() itemcnt, imgindex = 0, 0 sections = OrderedDict() sections.setdefault('test', []) sections['test'].append(('test title', 'test brief', 'article content')) sections.setdefault('test2', []) sections['test2'].append(('test2 title', 'test2 brief', 'article2 content')) for k in self._metadata: self._oeb.metadata.add(k, self._metadata[k]) self._toc(sections) io = byteStringIO() o = MOBIOutput() o.convert(self._oeb, io, self._opts, log) f = open('test.mobi', 'wb') f.write(str(io.getvalue())) f.close()
def as_mobi(self): self.book = MOBIOutput() return self
def as_epub(self): self.book = EPUBOutput() return self
class Ebook: def __init__(self, ebook_name): self.opts = getOpts() self.oeb = CreateOeb(log, None, self.opts) self.ebook_name = ebook_name # 防止发出无内容的空书 self.has_content = False setMetaData(self.oeb, title=ebook_name) GENERATE_HTML_TOC = True GENERATE_TOC_THUMBNAIL = True self.insertHtmlToc = GENERATE_HTML_TOC self.insertThumbnail = GENERATE_TOC_THUMBNAIL self.sections = OrderedDict() self.book = MOBIOutput() def as_epub(self): self.book = EPUBOutput() return self def as_mobi(self): self.book = MOBIOutput() return self def add_section(self, book_name, chapter, content): self.sections.setdefault(book_name, []) self.sections[book_name].append( (chapter, "b", "c", "<body>" + content + "</body>")) return self def add_sections(self, bookname, sections): if not sections: return try: for title, content in sections: self.add_section(bookname, title, content) except Exception as e: print(e) self.has_content = True def get_byte_book(self): if not self.has_content: return None toc_thumbnails = { "c": "https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" } InsertToc(self.oeb, self.sections, toc_thumbnails, self.insertHtmlToc, self.insertThumbnail) byte_book = byteStringIO() self.book.convert(self.oeb, byte_book, self.opts, log) return byte_book.getvalue()
def ProcessComicRSS(self, username, user, feed): opts = None oeb = None # 创建 OEB #global log opts = getOpts(user.device, 'comic') oeb = CreateOeb(main.log, None, opts) pubtype = 'book:book:KindleEar' language = 'zh-cn' setMetaData(oeb, feed.title, language, local_time("%Y-%m-%d", user.timezone), pubtype=pubtype) oeb.container = ServerContainer(main.log) #guide id_, href = oeb.manifest.generate('masthead', DEFAULT_MASTHEAD) # size:600*60 oeb.manifest.add(id_, href, MimeFromFilename(DEFAULT_MASTHEAD)) oeb.guide.add('masthead', 'Masthead Image', href) id_, href = oeb.manifest.generate('cover', DEFAULT_COVER) item = oeb.manifest.add(id_, href, MimeFromFilename(DEFAULT_COVER)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt, imgindex = 0, 0 sections = OrderedDict() toc_thumbnails = {} #map img-url -> manifest-href if feed.url.startswith(("http://ac.qq.com", "http://m.ac.qq.com")): book = TencentBaseBook(imgindex=imgindex, opts=opts, user=user) elif feed.url.startswith("http://www.cartoonmad.com"): book = CartoonMadBaseBook(imgindex=imgindex, opts=opts, user=user) else: return "Failed to push book <%s>!" % title book.title = feed.title book.description = feed.title book.language = language book.keep_image = True book.oldest_article = 7 book.fulltext_by_readability = True book.feeds = [(feed.title, feed.url)] book.url_filters = [flt.url for flt in user.urlfilter] 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)) return "Failed to push book <%s>!" % title volumeTitle = '' if itemcnt > 0: insertHtmlToc = False insertThumbnail = False volumeTitle = book.LastDeliveredVolume() oeb.metadata.clear('title') oeb.metadata.add('title', feed.title + volumeTitle) InsertToc(oeb, sections, toc_thumbnails, insertHtmlToc, insertThumbnail) oIO = byteStringIO() o = EPUBOutput() if user.book_type == "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, user.kindle_email, feed.title + volumeTitle, user.book_type, str(oIO.getvalue()), user.timezone) rs = "%s(%s).%s Sent!" % (feed.title, local_time(tz=user.timezone), user.book_type) main.log.info(rs) return rs else: self.deliverlog(username, str(user.kindle_email), feed.title + volumeTitle, 0, status='nonews', tz=user.timezone) 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 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 push_comic_book(self, username, user, book, opts=None): if not opts: opts = getOpts(user.device, "comic") oeb = CreateOeb(main.log, None, opts) pubtype = 'book:book:KindleEar' language = 'zh-cn' setMetaData( oeb, book.title, language, local_time("%Y-%m-%d", user.timezone), pubtype=pubtype, ) oeb.container = ServerContainer(main.log) #guide id_, href = oeb.manifest.generate('masthead', DEFAULT_MASTHEAD) # size:600*60 oeb.manifest.add(id_, href, MimeFromFilename(DEFAULT_MASTHEAD)) oeb.guide.add('masthead', 'Masthead Image', href) id_, href = oeb.manifest.generate('cover', DEFAULT_COVER) item = oeb.manifest.add(id_, href, MimeFromFilename(DEFAULT_COVER)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt, imgindex = 0, 0 sections = OrderedDict() toc_thumbnails = {} #map img-url -> manifest-href chapters = book.ParseFeedUrls() if not chapters: self.deliverlog( username, str(user.kindle_email), book.title, 0, status="nonews", tz=user.timezone, ) return for ( bookname, chapter_title, img_list, chapter_url, next_chapter_index, ) in chapters: try: image_count = 0 for ( mime_or_section, url, filename, content, brief, thumbnail, ) in book.gen_image_items(img_list, chapter_url): if not mime_or_section or not filename or not content: continue if mime_or_section.startswith(r"image/"): id_, href = oeb.manifest.generate(id="img", href=filename) item = oeb.manifest.add(id_, href, mime_or_section, data=content) if thumbnail: toc_thumbnails[url] = href else: sections.setdefault(mime_or_section, []) sections[mime_or_section].append( (filename, brief, thumbnail, content)) image_count += 1 title = book.title + " " + chapter_title if not image_count: self.deliverlog( username, str(user.kindle_email), title, 0, status="can't download image", tz=user.timezone, ) rs = "No new feeds." main.log.info(rs) continue insertHtmlToc = False insertThumbnail = False oeb.metadata.clear("title") oeb.metadata.add("title", title) InsertToc(oeb, sections, toc_thumbnails, insertHtmlToc, insertThumbnail) oIO = byteStringIO() o = EPUBOutput() if user.book_type == "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, user.kindle_email, title, user.book_type, str(oIO.getvalue()), user.timezone, ) book.UpdateLastDelivered(bookname, chapter_title, next_chapter_index) rs = "%s(%s).%s Sent!" % ( title, local_time(tz=user.timezone), user.book_type, ) main.log.info(rs) except: main.log.exception(u"Failed to push {} {}".format( bookname, chapter_title))
def createMobi(bk): opts = makeoeb.getOpts('kindlepw') oeb = makeoeb.CreateOeb(default_log, None, opts) title = bk.title makeoeb.setMetaData(oeb, title) oeb.container = makeoeb.ServerContainer() # cover mhfile = bk.masthead_path coverfile = bk.cover_path if mhfile: id_, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id_, href, makeoeb.MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) if coverfile: id_, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id_, href, makeoeb.MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt, imgindex = 0, 0 from collections import OrderedDict sections = OrderedDict() toc_thumbnails = {} # map img-url -> manifest-href if not bk: default_log.warn('not exist book <%s>' % bk.title) book = base.BaseFeedBook(imgindex=imgindex) book.title = bk.title book.description = bk.desc book.language = bk.lang book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed["title"], feed["url"], feed["fulltext"]) for feed in feeds] try: for sec_or_media, url, title, content, brief, thumbnail 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) 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: default_log.warn("Failure in pushing book '%s' : %s" % (book.title, str(e))) print itemcnt if itemcnt > 0: from utils import InsertToc InsertToc(oeb, sections, toc_thumbnails) oIO = byteStringIO() o = MOBIOutput() o.convert(oeb, oIO, opts, default_log) of_name = "/tmp/"+ time.strftime("%Y-%m-%d_%H%M%S", time.localtime()) + ".mobi" with open(of_name, "w") as f: f.write(str(oIO.getvalue())) return of_name return ""
def createMobi(bk): opts = makeoeb.getOpts('kindlepw') oeb = makeoeb.CreateOeb(default_log, None, opts) title = bk.title makeoeb.setMetaData(oeb, title) oeb.container = makeoeb.ServerContainer() # cover mhfile = bk.masthead_path coverfile = bk.cover_path if mhfile: id_, href = oeb.manifest.generate('masthead', mhfile) # size:600*60 oeb.manifest.add(id_, href, makeoeb.MimeFromFilename(mhfile)) oeb.guide.add('masthead', 'Masthead Image', href) if coverfile: id_, href = oeb.manifest.generate('cover', coverfile) item = oeb.manifest.add(id_, href, makeoeb.MimeFromFilename(coverfile)) oeb.guide.add('cover', 'Cover', href) oeb.metadata.add('cover', id_) itemcnt, imgindex = 0, 0 from collections import OrderedDict sections = OrderedDict() toc_thumbnails = {} # map img-url -> manifest-href if not bk: default_log.warn('not exist book <%s>' % bk.title) book = base.BaseFeedBook(imgindex=imgindex) book.title = bk.title book.description = bk.desc book.language = bk.lang book.oldest_article = bk.oldest_article book.fulltext_by_readability = True feeds = bk.feeds book.feeds = [(feed["title"], feed["url"], feed["fulltext"]) for feed in feeds] try: for sec_or_media, url, title, content, brief, thumbnail 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) 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: default_log.warn("Failure in pushing book '%s' : %s" % (book.title, str(e))) print itemcnt if itemcnt > 0: from utils import InsertToc InsertToc(oeb, sections, toc_thumbnails) oIO = byteStringIO() o = MOBIOutput() o.convert(oeb, oIO, opts, default_log) of_name = "/tmp/" + time.strftime("%Y-%m-%d_%H%M%S", time.localtime()) + ".mobi" with open(of_name, "w") as f: f.write(str(oIO.getvalue())) return of_name return ""