Commit d29d079d authored by Jack Darlington's avatar Jack Darlington

Now shows read in website, and can be toggled by clicking, two extra options...

Now shows read in website, and can be toggled by clicking, two extra options in sidebar (read/unread books)
parent 3cadde65
...@@ -100,6 +100,18 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 ...@@ -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: ...@@ -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): ...@@ -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: ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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(): ...@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment