diff --git a/cps/helper.py b/cps/helper.py index 2834bad1..43fb8520 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -114,9 +114,9 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False): return def check_send_to_kindle(entry): - ''' + """ returns all available book formats for sending to Kindle - ''' + """ if len(entry.data): bookformats=list() if ub.config.config_ebookconverter == 0: @@ -156,6 +156,18 @@ def check_send_to_kindle(entry): return None +# Check if a reader is existing for any of the book formats, if not, return empty list, otherwise return +# list with supported formats +def check_read_formats(entry): + EXTENSIONS_READER = {'TXT', 'PDF', 'EPUB', 'ZIP', 'CBZ', 'TAR', 'CBT', 'RAR', 'CBR'} + bookformats = list() + if len(entry.data): + for ele in iter(entry.data): + if ele.format in EXTENSIONS_READER: + bookformats.append(ele.format.lower()) + return bookformats + + # Files are processed in the following order/priority: # 1: If Mobi file is existing, it's directly send to kindle email, # 2: If Epub file is existing, it's converted and send to kindle email, @@ -336,6 +348,7 @@ def delete_book_gdrive(book, book_format): error =_(u'Book path %(path)s not found on Google Drive', path=book.path) # file not found return error + def generate_random_password(): s = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&*()?" passlen = 8 @@ -349,12 +362,14 @@ def update_dir_stucture(book_id, calibrepath): else: return update_dir_structure_file(book_id, calibrepath) + def delete_book(book, calibrepath, book_format): if ub.config.config_use_google_drive: return delete_book_gdrive(book, book_format) else: return delete_book_file(book, calibrepath, book_format) + def get_book_cover(cover_path): if ub.config.config_use_google_drive: try: @@ -372,6 +387,7 @@ def get_book_cover(cover_path): else: return send_from_directory(os.path.join(ub.config.config_calibre_dir, cover_path), "cover.jpg") + # saves book cover to gdrive or locally def save_cover(url, book_path): img = requests.get(url) @@ -384,7 +400,7 @@ def save_cover(url, book_path): f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb") f.write(img.content) f.close() - uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'), os.path.join(tmpDir, f.name)) + gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'), os.path.join(tmpDir, f.name)) web.app.logger.info("Cover is saved on Google Drive") return True @@ -394,6 +410,7 @@ def save_cover(url, book_path): web.app.logger.info("Cover is saved") return True + def do_download_file(book, book_format, data, headers): if ub.config.config_use_google_drive: startTime = time.time() @@ -621,6 +638,7 @@ def get_current_version_info(): return {'hash': content[0], 'datetime': content[1]} return False + def json_serial(obj): """JSON serializer for objects not serializable by default json code""" @@ -628,6 +646,7 @@ def json_serial(obj): return obj.isoformat() raise TypeError ("Type %s not serializable" % type(obj)) + def render_task_status(tasklist): #helper function to apply localize status information in tasklist entries renderedtasklist=list() diff --git a/cps/templates/detail.html b/cps/templates/detail.html index 27d73ae2..7631ce2f 100644 --- a/cps/templates/detail.html +++ b/cps/templates/detail.html @@ -57,17 +57,15 @@ {% endif %} {% endif %} - {% if entry.data|length %} + {% if reader_list %}
diff --git a/cps/web.py b/cps/web.py index 687a792c..558479cf 100644 --- a/cps/web.py +++ b/cps/web.py @@ -56,7 +56,6 @@ import tempfile from redirect import redirect_back import time import server -# import copy from reverseproxy import ReverseProxied try: @@ -116,8 +115,6 @@ EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'fb2', 'html', 'rtf', 'odt'} EXTENSIONS_CONVERT = {'pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'html', 'rtf', 'odt'} -# EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] + (['rar','cbr'] if rar_support else [])) - # Main code mimetypes.init() @@ -733,7 +730,8 @@ def feed_hot(): # ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete() # ub.session.commit() numBooks = entries.__len__() - pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, numBooks) + pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), + config.config_books_per_page, numBooks) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -773,7 +771,8 @@ def feed_publisherindex(): def feed_publisher(book_id): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), - db.Books, db.Books.publishers.any(db.Publishers.id == book_id), [db.Books.timestamp.desc()]) + db.Books, db.Books.publishers.any(db.Publishers.id == book_id), + [db.Books.timestamp.desc()]) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -872,7 +871,8 @@ def get_opds_download_link(book_id, book_format): file_name = book.authors[0].name + '_' + file_name file_name = helper.get_valid_filename(file_name) headers = Headers() - headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf8')), book_format) + headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf8')), + book_format) try: headers["Content-Type"] = mimetypes.types_map['.' + book_format] except KeyError: @@ -895,32 +895,8 @@ def get_metadata_calibre_companion(uuid): @app.route("/ajax/emailstat") @login_required def get_email_status_json(): - answer=list() - # UIanswer = list() tasks=helper.global_WorkerThread.get_taskstatus() - '''if not current_user.role_admin(): - for task in tasks: - if task['user'] == current_user.nickname: - if task['formStarttime']: - task['starttime'] = format_datetime(task['formStarttime'], format='short', locale=get_locale()) - # task['formStarttime'] = "" - else: - if 'starttime' not in task: - task['starttime'] = "" - answer.append(task) - else: - for task in tasks: - if task['formStarttime']: - task['starttime'] = format_datetime(task['formStarttime'], format='short', locale=get_locale()) - task['formStarttime'] = "" - else: - if 'starttime' not in task: - task['starttime'] = "" - answer = tasks''' - - # UIanswer = copy.deepcopy(answer) answer = helper.render_task_status(tasks) - js=json.dumps(answer, default=helper.json_serial) response = make_response(js) response.headers["Content-Type"] = "application/json; charset=utf-8" @@ -1423,7 +1399,7 @@ def author_list(): @login_required_if_no_ano def author(book_id, page): entries, __, pagination = fill_indexpage(page, db.Books, db.Books.authors.any(db.Authors.id == book_id), - [db.Series.name, db.Books.series_index],db.books_series_link, db.Series) + [db.Series.name, db.Books.series_index],db.books_series_link, db.Series) if entries is None: flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error") return redirect(url_for("index")) @@ -1464,8 +1440,9 @@ def publisher_list(): def publisher(book_id, page): publisher = db.session.query(db.Publishers).filter(db.Publishers.id == book_id).first() if publisher: - entries, random, pagination = fill_indexpage(page, db.Books, db.Books.publishers.any(db.Publishers.id == book_id), - (db.Series.name, db.Books.series_index), db.books_series_link, db.Series) + entries, random, pagination = fill_indexpage(page, db.Books, + db.Books.publishers.any(db.Publishers.id == book_id), + (db.Series.name, db.Books.series_index), db.books_series_link, db.Series) return render_title_template('index.html', random=random, entries=entries, pagination=pagination, title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher") else: @@ -1675,10 +1652,11 @@ def show_book(book_id): entries.tags = sort(entries.tags, key = lambda tag: tag.name) kindle_list = helper.check_send_to_kindle(entries) + reader_list = helper.check_read_formats(entries) return render_title_template('detail.html', entry=entries, cc=cc, is_xhr=request.is_xhr, title=entries.title, books_shelfs=book_in_shelfs, - have_read=have_read, kindle_list=kindle_list, page="book") + have_read=have_read, kindle_list=kindle_list, reader_list=reader_list, page="book") else: flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error") return redirect(url_for("index")) @@ -1795,7 +1773,8 @@ def delete_book(book_id, book_format): getattr(book, cc_string).remove(del_cc) db.session.delete(del_cc) else: - modify_database_object([u''], getattr(book, cc_string), db.cc_classes[c.id], db.session, 'custom') + modify_database_object([u''], getattr(book, cc_string), db.cc_classes[c.id], + db.session, 'custom') db.session.query(db.Books).filter(db.Books.id == book_id).delete() else: db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format).delete() @@ -1871,7 +1850,8 @@ def revoke_watch_gdrive(): last_watch_response = config.config_google_drive_watch_changes_response if last_watch_response: try: - gdriveutils.stopChannel(gdriveutils.Gdrive.Instance().drive, last_watch_response['id'], last_watch_response['resourceId']) + gdriveutils.stopChannel(gdriveutils.Gdrive.Instance().drive, last_watch_response['id'], + last_watch_response['resourceId']) except HttpError: pass settings = ub.session.query(ub.Settings).first() @@ -2467,7 +2447,8 @@ def send_to_kindle(book_id, book_format, convert): if settings.get("mail_server", "mail.example.com") == "mail.example.com": flash(_(u"Please configure the SMTP mail settings first..."), category="error") elif current_user.kindle_mail: - result = helper.send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir, current_user.nickname) + result = helper.send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir, + current_user.nickname) if result is None: flash(_(u"Book successfully queued for sending to %(kindlemail)s", kindlemail=current_user.kindle_mail), category="success") @@ -2625,7 +2606,8 @@ def remove_from_shelf(shelf_id, book_id): else: app.logger.info("Sorry you are not allowed to remove a book from this shelf: %s" % shelf.name) if not request.is_xhr: - flash(_(u"Sorry you are not allowed to remove a book from this shelf: %(sname)s", sname=shelf.name), category="error") + flash(_(u"Sorry you are not allowed to remove a book from this shelf: %(sname)s", sname=shelf.name), + category="error") return redirect(url_for('index')) return "Sorry you are not allowed to remove a book from this shelf: %s" % shelf.name, 403 @@ -3111,9 +3093,9 @@ def configuration_helper(origin): content.config_rarfile_location = to_save["config_rarfile_location"].strip() else: flash(check[1], category="error") - return render_title_template("config_edit.html", content=config, origin=origin, gdrive=gdriveutils.gdrive_support, - goodreads=goodreads_support, rarfile_support=rar_support, - title=_(u"Basic Configuration")) + return render_title_template("config_edit.html", content=config, origin=origin, + gdrive=gdriveutils.gdrive_support, goodreads=goodreads_support, + rarfile_support=rar_support, title=_(u"Basic Configuration")) try: if content.config_use_google_drive and is_gdrive_ready() and not os.path.exists(config.config_calibre_dir + "/metadata.db"): gdriveutils.downloadFile(None, "metadata.db", config.config_calibre_dir + "/metadata.db") @@ -3128,15 +3110,17 @@ def configuration_helper(origin): logging.getLogger("book_formats").setLevel(config.config_log_level) except Exception as e: flash(e, category="error") - return render_title_template("config_edit.html", content=config, origin=origin, gdrive=gdriveutils.gdrive_support, - gdriveError=gdriveError, goodreads=goodreads_support, rarfile_support=rar_support, + return render_title_template("config_edit.html", content=config, origin=origin, + gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError, + goodreads=goodreads_support, rarfile_support=rar_support, title=_(u"Basic Configuration"), page="config") if db_change: reload(db) if not db.setup_db(): flash(_(u'DB location is not valid, please enter correct path'), category="error") - return render_title_template("config_edit.html", content=config, origin=origin, gdrive=gdriveutils.gdrive_support, - gdriveError=gdriveError, goodreads=goodreads_support, rarfile_support=rar_support, + return render_title_template("config_edit.html", content=config, origin=origin, + gdrive=gdriveutils.gdrive_support,gdriveError=gdriveError, + goodreads=goodreads_support, rarfile_support=rar_support, title=_(u"Basic Configuration"), page="config") if reboot_required: # stop Server @@ -3150,8 +3134,9 @@ def configuration_helper(origin): else: gdrivefolders=list() return render_title_template("config_edit.html", origin=origin, success=success, content=config, - show_authenticate_google_drive=not is_gdrive_ready(), gdrive=gdriveutils.gdrive_support, - gdriveError=gdriveError, gdrivefolders=gdrivefolders, rarfile_support=rar_support, + show_authenticate_google_drive=not is_gdrive_ready(), + gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError, + gdrivefolders=gdrivefolders, rarfile_support=rar_support, goodreads=goodreads_support, title=_(u"Basic Configuration"), page="config") @@ -3581,7 +3566,8 @@ def upload_single_file(request, book, book_id): return redirect(url_for('show_book', book_id=book.id)) file_size = os.path.getsize(saved_filename) - is_format = db.session.query(db.Data).filter(db.Data.book == book_id).filter(db.Data.format == file_ext.upper()).first() + is_format = db.session.query(db.Data).filter(db.Data.book == book_id).\ + filter(db.Data.format == file_ext.upper()).first() # Format entry already exists, no need to update the database if is_format: @@ -3611,7 +3597,8 @@ def upload_cover(request, book): try: os.makedirs(filepath) except OSError: - flash(_(u"Failed to create path for cover %(path)s (Permission denied).", cover=filepath), category="error") + flash(_(u"Failed to create path for cover %(path)s (Permission denied).", cover=filepath), + category="error") return redirect(url_for('show_book', book_id=book.id)) try: requested_file.save(saved_filename) @@ -3826,11 +3813,13 @@ def upload(): try: os.unlink(meta.file_path) except OSError: - flash(_(u"Failed to delete file %(file)s (Permission denied).", file= meta.file_path), category="warning") + flash(_(u"Failed to delete file %(file)s (Permission denied).", file= meta.file_path), + category="warning") if meta.cover is None: has_cover = 0 - copyfile(os.path.join(config.get_main_dir, "cps/static/generic_cover.jpg"), os.path.join(filepath, "cover.jpg")) + copyfile(os.path.join(config.get_main_dir, "cps/static/generic_cover.jpg"), + os.path.join(filepath, "cover.jpg")) else: has_cover = 1 move(meta.cover, os.path.join(filepath, "cover.jpg")) @@ -3896,8 +3885,7 @@ def upload(): # save data to database, reread data db.session.commit() db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort) - book = db.session.query(db.Books) \ - .filter(db.Books.id == book_id).filter(common_filters()).first() + book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first() # upload book to gdrive if nesseccary and add "(bookid)" to folder name if config.config_use_google_drive: @@ -3919,14 +3907,18 @@ def upload(): for author in db_book.authors: author_names.append(author.name) if len(request.files.getlist("btn-upload")) < 2: - cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns. + datatype.notin_(db.cc_exceptions)).all() if current_user.role_edit() or current_user.role_admin(): return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc, title=_(u"edit metadata"), page="upload") book_in_shelfs = [] - flg_send_to_kindle = helper.chk_send_to_kindle(book_id) + kindle_list = helper.check_send_to_kindle(book) + reader_list = helper.check_read_formats(book) + return render_title_template('detail.html', entry=book, cc=cc, - title=book.title, books_shelfs=book_in_shelfs, flg_kindle=flg_send_to_kindle, page="upload") + title=book.title, books_shelfs=book_in_shelfs, kindle_list=kindle_list, + reader_list=reader_list, page="upload") return redirect(url_for("index"))