From 374b5f4c6e4e6aaf4fa775d5e05f2d011ccd5409 Mon Sep 17 00:00:00 2001 From: Jonathan Rehm Date: Wed, 23 Aug 2017 08:52:52 -0700 Subject: [PATCH] Save ePub bookmarks to database Save ePub bookmark to database. Also use library's built-in restore feature to restore all information from localStorage. --- cps/static/js/reading/epub.js | 38 +++++++++++++ cps/templates/read.html | 70 ++++++----------------- cps/ub.py | 19 ++++++- cps/web.py | 102 +++++++++++++++++++++------------- 4 files changed, 133 insertions(+), 96 deletions(-) create mode 100644 cps/static/js/reading/epub.js diff --git a/cps/static/js/reading/epub.js b/cps/static/js/reading/epub.js new file mode 100644 index 00000000..d8de6f5b --- /dev/null +++ b/cps/static/js/reading/epub.js @@ -0,0 +1,38 @@ +/* global $, calibre, EPUBJS, ePubReader */ + +(function() { + "use strict"; + + EPUBJS.filePath = calibre.filePath; + EPUBJS.cssPath = calibre.cssPath; + + var reader = ePubReader(calibre.bookUrl, { + restore: true, + bookmarks: [calibre.bookmark] + }); + reader.on("reader:bookmarked", updateBookmark.bind(reader, "add")); + reader.on("reader:unbookmarked", updateBookmark.bind(reader, "remove")); + + /** + * @param {string} action - Add or remove bookmark + * @param {string|int} location - Location or zero + */ + function updateBookmark(action, location) { + // Remove other bookmarks (there can only be one) + if (action === "add") { + this.settings.bookmarks.filter(function (bookmark) { + return bookmark !== location; + }).map(function (bookmark) { + this.removeBookmark(bookmark); + }.bind(this)); + } + + // Save to database + $.ajax(calibre.bookmarkUrl, { + method: "post", + data: { bookmark: location || "" } + }).fail(function (xhr, status, error) { + alert(error); + }); + } +})(); diff --git a/cps/templates/read.html b/cps/templates/read.html index d02f76d1..dc44ce9b 100644 --- a/cps/templates/read.html +++ b/cps/templates/read.html @@ -11,59 +11,6 @@ - - - - - - - - - - - - - - - - -
+ + + + + + + + + diff --git a/cps/ub.py b/cps/ub.py index 89c9cf28..a559db43 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -212,15 +212,26 @@ class BookShelf(Base): def __repr__(self): return '' % self.id + class ReadBook(Base): __tablename__ = 'book_read_link' - id=Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) book_id = Column(Integer, unique=False) - user_id =Column(Integer, ForeignKey('user.id'), unique=False) + user_id = Column(Integer, ForeignKey('user.id'), unique=False) is_read = Column(Boolean, unique=False) +class Bookmark(Base): + __tablename__ = 'bookmark' + + id = Column(Integer, primary_key=True) + user_id = Column(Integer, ForeignKey('user.id')) + book_id = Column(Integer) + format = Column(String(collation='NOCASE')) + bookmark_key = Column(String) + + # Baseclass representing Downloads from calibre-web in app.db class Downloads(Base): __tablename__ = 'downloads' @@ -396,7 +407,9 @@ class Config: # rows with SQL commands def migrate_Database(): if not engine.dialect.has_table(engine.connect(), "book_read_link"): - ReadBook.__table__.create(bind = engine) + ReadBook.__table__.create(bind=engine) + if not engine.dialect.has_table(engine.connect(), "bookmark"): + Bookmark.__table__.create(bind=engine) try: session.query(exists().where(User.locale)).scalar() diff --git a/cps/web.py b/cps/web.py index 19673453..a0ef6909 100755 --- a/cps/web.py +++ b/cps/web.py @@ -1354,6 +1354,26 @@ def show_book(book_id): return redirect(url_for("index")) +@app.route("/ajax/bookmark//", methods=['POST']) +@login_required +def bookmark(book_id, book_format): + bookmark_key = request.form["bookmark"] + ub.session.query(ub.Bookmark).filter(ub.and_(ub.Bookmark.user_id == int(current_user.id), + ub.Bookmark.book_id == book_id, + ub.Bookmark.format == book_format)).delete() + if not bookmark_key: + ub.session.commit() + return "", 204 + + bookmark = ub.Bookmark(user_id=current_user.id, + book_id=book_id, + format=book_format, + bookmark_key=bookmark_key) + ub.session.merge(bookmark) + ub.session.commit() + return "", 201 + + @app.route("/admin") @login_required def admin_forbidden(): @@ -1794,49 +1814,51 @@ def unread_books(page): @login_required_if_no_ano def read_book(book_id, book_format): book = db.session.query(db.Books).filter(db.Books.id == book_id).first() - if book: - book_dir = os.path.join(config.get_main_dir, "cps", "static", str(book_id)) - if not os.path.exists(book_dir): - os.mkdir(book_dir) - if book_format.lower() == "epub": - # check if mimetype file is exists - mime_file = str(book_id) + "/mimetype" - if not os.path.exists(mime_file): - epub_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".epub" - if not os.path.isfile(epub_file): - raise ValueError('Error opening eBook. File does not exist: ', epub_file) - zfile = zipfile.ZipFile(epub_file) - for name in zfile.namelist(): - (dirName, fileName) = os.path.split(name) - newDir = os.path.join(book_dir, dirName) - if not os.path.exists(newDir): - try: - os.makedirs(newDir) - except OSError as exception: - if not exception.errno == errno.EEXIST: - raise - if fileName: - fd = open(os.path.join(newDir, fileName), "wb") - fd.write(zfile.read(name)) - fd.close() - zfile.close() - return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book")) - elif book_format.lower() == "pdf": - return render_title_template('readpdf.html', pdffile=book_id, title=_(u"Read a Book")) - elif book_format.lower() == "txt": - return render_title_template('readtxt.html', txtfile=book_id, title=_(u"Read a Book")) - elif book_format.lower() == "cbr": - all_name = str(book_id) + "/" + book.data[0].name + ".cbr" - tmp_file = os.path.join(book_dir, book.data[0].name) + ".cbr" - if not os.path.exists(all_name): - cbr_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".cbr" - copyfile(cbr_file, tmp_file) - return render_title_template('readcbr.html', comicfile=all_name, title=_(u"Read a Book")) - - else: + if not book: flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error") return redirect(url_for("index")) + book_dir = os.path.join(config.get_main_dir, "cps", "static", str(book_id)) + if not os.path.exists(book_dir): + os.mkdir(book_dir) + bookmark = ub.session.query(ub.Bookmark).filter(ub.and_(ub.Bookmark.user_id == int(current_user.id), + ub.Bookmark.book_id == book_id, + ub.Bookmark.format == book_format.upper())).first() + if book_format.lower() == "epub": + # check if mimetype file is exists + mime_file = str(book_id) + "/mimetype" + if not os.path.exists(mime_file): + epub_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".epub" + if not os.path.isfile(epub_file): + raise ValueError('Error opening eBook. File does not exist: ', epub_file) + zfile = zipfile.ZipFile(epub_file) + for name in zfile.namelist(): + (dirName, fileName) = os.path.split(name) + newDir = os.path.join(book_dir, dirName) + if not os.path.exists(newDir): + try: + os.makedirs(newDir) + except OSError as exception: + if not exception.errno == errno.EEXIST: + raise + if fileName: + fd = open(os.path.join(newDir, fileName), "wb") + fd.write(zfile.read(name)) + fd.close() + zfile.close() + return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"), bookmark=bookmark) + elif book_format.lower() == "pdf": + return render_title_template('readpdf.html', pdffile=book_id, title=_(u"Read a Book")) + elif book_format.lower() == "txt": + return render_title_template('readtxt.html', txtfile=book_id, title=_(u"Read a Book")) + elif book_format.lower() == "cbr": + all_name = str(book_id) + "/" + book.data[0].name + ".cbr" + tmp_file = os.path.join(book_dir, book.data[0].name) + ".cbr" + if not os.path.exists(all_name): + cbr_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".cbr" + copyfile(cbr_file, tmp_file) + return render_title_template('readcbr.html', comicfile=all_name, title=_(u"Read a Book")) + @app.route("/download//") @login_required_if_no_ano