Save ePub bookmarks to database

Save ePub bookmark to database. Also use library's built-in restore feature to restore all information from localStorage.
This commit is contained in:
Jonathan Rehm 2017-08-23 08:52:52 -07:00
parent 193605df4a
commit 374b5f4c6e
4 changed files with 133 additions and 96 deletions

View File

@ -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);
});
}
})();

View File

@ -11,59 +11,6 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/libs/normalize.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/libs/normalize.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/popup.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/popup.css') }}">
<script src="{{ url_for('static', filename='js/libs/jquery.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/zip.min.js') }}"></script>
<!-- Full Screen -->
<script src="{{ url_for('static', filename='js/libs/screenfull.min.js') }}"></script>
<!-- Render -->
<script src="{{ url_for('static', filename='js/libs/epub.min.js') }}"></script>
<!-- Hooks -->
<script src="{{ url_for('static', filename='js/libs/hooks.min.js') }}"></script>
<!-- Reader -->
<script src="{{ url_for('static', filename='js/libs/reader.min.js') }}"></script>
<script>
"use strict";
document.onreadystatechange = function () {
if (document.readyState == "complete") {
EPUBJS.filePath = "{{ url_for('static', filename='js/libs/') }}";
EPUBJS.cssPath = "{{ url_for('static', filename='css/') }}";
window.reader = ePubReader("{{ url_for('static', filename=bookid) }}/");
//keybind
/*$(document).keydown(function(event){
if(event.keyCode == 37){
//window.reader.book.prevPage();
event.preventDefault();
}
if(event.keyCode == 39){
//swindow.reader.book.nextPage();
event.preventDefault();
}
});
//bind mouse
$(window).bind('DOMMouseScroll mousewheel', function(event) {
var delta = 0;
if (event.originalEvent.wheelDelta) {
delta = event.originalEvent.wheelDelta;
}else if (event.originalEvent.detail) {
delta = event.originalEvent.detail*-1;
}
if (delta >= 0) {
window.reader.book.prevPage();
}
else {
window.reader.book.nextPage();
}
});*/
}
};
</script>
</head> </head>
<body> <body>
<div id="sidebar"> <div id="sidebar">
@ -129,5 +76,22 @@
</div> </div>
</div> </div>
<div class="overlay"></div> <div class="overlay"></div>
<script type="text/javascript">
window.calibre = {
filePath: "{{ url_for('static', filename='js/libs/') }}",
cssPath: "{{ url_for('static', filename='css/') }}",
bookUrl: "{{ url_for('static', filename=bookid) }}/",
bookmarkUrl: "{{ url_for('bookmark', book_id=bookid, book_format='EPUB') }}",
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}"
};
</script>
<script src="{{ url_for('static', filename='js/libs/jquery.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/zip.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/screenfull.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/epub.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/hooks.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/reader.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/reading/epub.js') }}"></script>
</body> </body>
</html> </html>

View File

@ -212,15 +212,26 @@ class BookShelf(Base):
def __repr__(self): def __repr__(self):
return '<Book %r>' % self.id return '<Book %r>' % self.id
class ReadBook(Base): class ReadBook(Base):
__tablename__ = 'book_read_link' __tablename__ = 'book_read_link'
id=Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
book_id = Column(Integer, unique=False) 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) 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 # Baseclass representing Downloads from calibre-web in app.db
class Downloads(Base): class Downloads(Base):
__tablename__ = 'downloads' __tablename__ = 'downloads'
@ -396,7 +407,9 @@ class Config:
# rows with SQL commands # rows with SQL commands
def migrate_Database(): def migrate_Database():
if not engine.dialect.has_table(engine.connect(), "book_read_link"): 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: try:
session.query(exists().where(User.locale)).scalar() session.query(exists().where(User.locale)).scalar()

View File

@ -1354,6 +1354,26 @@ def show_book(book_id):
return redirect(url_for("index")) return redirect(url_for("index"))
@app.route("/ajax/bookmark/<int:book_id>/<book_format>", 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") @app.route("/admin")
@login_required @login_required
def admin_forbidden(): def admin_forbidden():
@ -1794,49 +1814,51 @@ def unread_books(page):
@login_required_if_no_ano @login_required_if_no_ano
def read_book(book_id, book_format): def read_book(book_id, book_format):
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
if book: if not 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:
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error") flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
return redirect(url_for("index")) 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/<int:book_id>/<book_format>") @app.route("/download/<int:book_id>/<book_format>")
@login_required_if_no_ano @login_required_if_no_ano