Now shows read in website, and can be toggled by clicking, two extra options in sidebar (read/unread books)

pull/118/head
Jack Darlington 8 years ago
parent 3cadde6579
commit d29d079d15

@ -100,6 +100,18 @@
</div> </div>
</p> </p>
{% endif %} {% endif %}
<p>
<div class="custom_columns" id="have_read">
Read
{% if have_read %}
<span class="glyphicon glyphicon-ok"></span>
{% else %}
<span class="glyphicon glyphicon-remove"></span>
{% endif %}
<form id="have_read_form" action="{{ url_for('toggle_read', id=entry.id)}}" method="POST") >
</form>
</div>
</p>
{% if entry.comments|length > 0 and entry.comments[0].text|length > 0%} {% if entry.comments|length > 0 and entry.comments[0].text|length > 0%}
@ -201,3 +213,34 @@
</div> </div>
{% endblock %} {% endblock %}
{% block js %}
<script src="http://malsup.github.com/jquery.form.js"></script>
<script>
$( document ).ready(function() {
var haveReadForm = $('#have_read_form');
haveReadForm.ajaxForm();
});
$("#have_read").attr('unselectable','on')
.css({'-moz-user-select':'-moz-none',
'-moz-user-select':'none',
'-o-user-select':'none',
'-khtml-user-select':'none', /* you could also put this in a class */
'-webkit-user-select':'none',/* and add the CSS class here instead */
'-ms-user-select':'none',
'user-select':'none'
}).bind('selectstart', function(){ return false; });
$("#have_read").click(function() {
var haveReadForm = $('#have_read_form');
if ($("#have_read").find('span').hasClass('glyphicon-ok')) {
$("#have_read").find('span').removeClass('glyphicon-ok');
$("#have_read").find('span').addClass('glyphicon-remove');
} else {
$("#have_read").find('span').removeClass('glyphicon-remove');
$("#have_read").find('span').addClass('glyphicon-ok');
}
haveReadForm.submit()
});
</script>
{% endblock %}

@ -128,6 +128,10 @@
{% if g.user.show_best_rated_books() %} {% if g.user.show_best_rated_books() %}
<li><a href="{{url_for('best_rated_books')}}"><span class="glyphicon glyphicon-star"></span> {{_('Best rated Books')}}</a></li> <li><a href="{{url_for('best_rated_books')}}"><span class="glyphicon glyphicon-star"></span> {{_('Best rated Books')}}</a></li>
{%endif%} {%endif%}
{% if g.user.show_read_and_unread() %}
<li><a href="{{url_for('read_books')}}"><span class="glyphicon glyphicon-eye-open"></span> {{_('Read Books')}}</a></li>
<li><a href="{{url_for('unread_books')}}"><span class="glyphicon glyphicon-eye-close"></span> {{_('Unread Books')}}</a></li>
{%endif%}
{% if g.user.show_random_books() %} {% if g.user.show_random_books() %}
<li id="nav_rand"><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li> <li id="nav_rand"><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li>
{%endif%} {%endif%}

@ -68,6 +68,10 @@
<input type="checkbox" name="show_author" id="show_author" {% if content.show_author() %}checked{% endif %}> <input type="checkbox" name="show_author" id="show_author" {% if content.show_author() %}checked{% endif %}>
<label for="show_author">{{_('Show author selection')}}</label> <label for="show_author">{{_('Show author selection')}}</label>
</div> </div>
<div class="form-group">
<input type="checkbox" name="show_read_and_unread" id="show_read_and_unread" {% if content.show_read_and_unread() %}checked{% endif %}>
<label for="show_read_and_unread">{{_('Show read and unread')}}</label>
</div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_detail_random" id="show_detail_random" {% if content.show_detail_random() %}checked{% endif %}> <input type="checkbox" name="show_detail_random" id="show_detail_random" {% if content.show_detail_random() %}checked{% endif %}>
<label for="show_detail_random">{{_('Show random books in detail view')}}</label> <label for="show_detail_random">{{_('Show random books in detail view')}}</label>

@ -32,6 +32,7 @@ SIDEBAR_HOT = 16
SIDEBAR_RANDOM = 32 SIDEBAR_RANDOM = 32
SIDEBAR_AUTHOR = 64 SIDEBAR_AUTHOR = 64
SIDEBAR_BEST_RATED = 128 SIDEBAR_BEST_RATED = 128
SIDEBAR_READ_AND_UNREAD = 256
DEFAULT_PASS = "admin123" DEFAULT_PASS = "admin123"
DEFAULT_PORT = int(os.environ.get("CALIBRE_PORT", 8083)) DEFAULT_PORT = int(os.environ.get("CALIBRE_PORT", 8083))
@ -138,6 +139,12 @@ class UserBase:
else: else:
return False return False
def show_read_and_unread(self):
if self.sidebar_view is not None:
return True if self.sidebar_view & SIDEBAR_READ_AND_UNREAD == SIDEBAR_READ_AND_UNREAD else False
else:
return False
def show_detail_random(self): def show_detail_random(self):
if self.sidebar_view is not None: if self.sidebar_view is not None:
return True if self.sidebar_view & DETAIL_RANDOM == DETAIL_RANDOM else False return True if self.sidebar_view & DETAIL_RANDOM == DETAIL_RANDOM else False
@ -218,6 +225,14 @@ class BookShelf(Base):
def __repr__(self): def __repr__(self):
return '<Book %r>' % self.id return '<Book %r>' % self.id
class ReadBook(Base):
__tablename__ = 'book_read_link'
id=Column(Integer, primary_key=True)
book_id = Column(Integer, unique=False)
user_id =Column(Integer, ForeignKey('user.id'), unique=False)
is_read = Column(Boolean, unique=False)
# Baseclass representing Downloads from calibre-web in app.db # Baseclass representing Downloads from calibre-web in app.db
class Downloads(Base): class Downloads(Base):
@ -336,6 +351,9 @@ class Config:
# everywhere to curent should work. Migration is done by checking if relevant coloums are existing, and than adding # everywhere to curent should work. Migration is done by checking if relevant coloums are existing, and than adding
# 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"):
ReadBook.__table__.create(bind = engine)
try: try:
session.query(exists().where(User.locale)).scalar() session.query(exists().where(User.locale)).scalar()
session.commit() session.commit()

@ -953,6 +953,23 @@ def category(id, page):
title=_(u"Category: %(name)s", name=name)) title=_(u"Category: %(name)s", name=name))
@app.route("/ajax/toggleread/<int:id>", methods=['POST'])
@login_required
def toggle_read(id):
book = ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
ub.ReadBook.book_id == id)).first()
if book:
book.is_read=not book.is_read
else:
readBook=ub.ReadBook()
readBook.user_id=int(current_user.id)
readBook.book_id = id
readBook.is_read=True
book=readBook
ub.session.merge(book)
ub.session.commit()
return ""
@app.route("/book/<int:id>") @app.route("/book/<int:id>")
@login_required_if_no_ano @login_required_if_no_ano
def show_book(id): def show_book(id):
@ -975,8 +992,14 @@ def show_book(id):
for entry in shelfs: for entry in shelfs:
book_in_shelfs.append(entry.shelf) book_in_shelfs.append(entry.shelf)
#return render_title_template('detail.html', entry=entries, cc=cc,
# title=entries.title, books_shelfs=book_in_shelfs)
matching_have_read_book=ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
ub.ReadBook.book_id == id)).all()
have_read=len(matching_have_read_book) > 0 and matching_have_read_book[0].is_read
return render_title_template('detail.html', entry=entries, cc=cc, return render_title_template('detail.html', entry=entries, cc=cc,
title=entries.title, books_shelfs=book_in_shelfs) title=entries.title, books_shelfs=book_in_shelfs, have_read=have_read)
else: 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"))
@ -1160,8 +1183,61 @@ def get_cover(cover_path):
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_get_cover(book_id): def feed_get_cover(book_id):
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()
return send_from_directory(os.path.join(config.config_calibre_dir, book.path), "cover.jpg") #return send_from_directory(os.path.join(config.config_calibre_dir, book.path), "cover.jpg")
df=gdriveutils.getFileFromEbooksFolder(book.path, 'cover.jpg', Gdrive.Instance().drive)
download_url = df.metadata.get('downloadUrl')
resp, content = df.auth.Get_Http_Object().request(download_url)
resp=make_response(content)
resp.headers['Content-Type']='image/jpeg'
return resp
def render_read_books(page, are_read, as_xml=False):
readBooks=ub.session.query(ub.ReadBook).filter(ub.ReadBook.user_id == int(current_user.id)).filter(ub.ReadBook.is_read == True).all()
readBookIds=[x.book_id for x in readBooks]
if are_read:
db_filter = db.Books.id.in_(readBookIds)
else:
db_filter = ~db.Books.id.in_(readBookIds)
entries, random, pagination = fill_indexpage(page, db.Books,
db_filter, db.Books.timestamp.desc())
if as_xml:
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
else:
name=u'Read Books' if are_read else u'Unread Books'
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
title=_(name, name=name))
@app.route("/opds/readbooks/")
@login_required_if_no_ano
def feed_read_books():
off = request.args.get("offset")
if not off:
off = 0
return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
@app.route("/readbooks/", defaults={'page': 1})
@app.route("/readbooks/<int:page>'")
@login_required_if_no_ano
def read_books(page):
return render_read_books(page, True)
@app.route("/opds/unreadbooks/")
@login_required_if_no_ano
def feed_unread_books():
off = request.args.get("offset")
if not off:
off = 0
return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
@app.route("/unreadbooks/", defaults={'page': 1})
@app.route("/unreadbooks/<int:page>'")
@login_required_if_no_ano
def unread_books(page):
return render_read_books(page, False)
@app.route("/read/<int:book_id>/<format>") @app.route("/read/<int:book_id>/<format>")
@login_required @login_required
@ -1240,6 +1316,10 @@ def get_download_link(book_id, format):
file_name = helper.get_valid_filename(file_name) file_name = helper.get_valid_filename(file_name)
response = make_response( response = make_response(
send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format)) send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
df=gdriveutils.getFileFromEbooksFolder(book.path, '%s.%s' % (data.name, format), Gdrive.Instance().drive)
download_url = df.metadata.get('downloadUrl')
resp, content = df.auth.Get_Http_Object().request(download_url)
#response=make_response(content)
try: try:
response.headers["Content-Type"] = mimetypes.types_map['.' + format] response.headers["Content-Type"] = mimetypes.types_map['.' + format]
except: except:
@ -1556,6 +1636,8 @@ def profile():
content.sidebar_view += ub.SIDEBAR_BEST_RATED content.sidebar_view += ub.SIDEBAR_BEST_RATED
if "show_author" in to_save: if "show_author" in to_save:
content.sidebar_view += ub.SIDEBAR_AUTHOR content.sidebar_view += ub.SIDEBAR_AUTHOR
if "show_read_and_unread" in to_save:
content.sidebar_view += ub.SIDEBAR_READ_AND_UNREAD
if "show_detail_random" in to_save: if "show_detail_random" in to_save:
content.sidebar_view += ub.DETAIL_RANDOM content.sidebar_view += ub.DETAIL_RANDOM
if "default_language" in to_save: if "default_language" in to_save:

Loading…
Cancel
Save