mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-30 23:03:02 +00:00 
			
		
		
		
	Refactored books detail page
This commit is contained in:
		
							
								
								
									
										52
									
								
								cps/db.py
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								cps/db.py
									
									
									
									
									
								
							| @@ -39,9 +39,8 @@ except ImportError: | ||||
| from sqlalchemy.pool import StaticPool | ||||
| from sqlalchemy.sql.expression import and_, true, false, text, func, or_ | ||||
| from sqlalchemy.ext.associationproxy import association_proxy | ||||
| from sqlalchemy.orm import joinedload | ||||
| from flask_login import current_user | ||||
| from babel import Locale as LC | ||||
| from babel.core import UnknownLocaleError | ||||
| from flask_babel import gettext as _ | ||||
| from flask import flash | ||||
|  | ||||
| @@ -338,15 +337,15 @@ class Books(Base): | ||||
|     isbn = Column(String(collation='NOCASE'), default="") | ||||
|     flags = Column(Integer, nullable=False, default=1) | ||||
|  | ||||
|     authors = relationship('Authors', secondary=books_authors_link, backref='books') | ||||
|     tags = relationship('Tags', secondary=books_tags_link, backref='books', order_by="Tags.name") | ||||
|     comments = relationship('Comments', backref='books') | ||||
|     data = relationship('Data', backref='books') | ||||
|     series = relationship('Series', secondary=books_series_link, backref='books') | ||||
|     ratings = relationship('Ratings', secondary=books_ratings_link, backref='books') | ||||
|     languages = relationship('Languages', secondary=books_languages_link, backref='books') | ||||
|     publishers = relationship('Publishers', secondary=books_publishers_link, backref='books') | ||||
|     identifiers = relationship('Identifiers', backref='books') | ||||
|     authors = relationship(Authors, secondary=books_authors_link, backref='books') | ||||
|     tags = relationship(Tags, secondary=books_tags_link, backref='books', order_by="Tags.name") | ||||
|     comments = relationship(Comments, backref='books') | ||||
|     data = relationship(Data, backref='books') | ||||
|     series = relationship(Series, secondary=books_series_link, backref='books') | ||||
|     ratings = relationship(Ratings, secondary=books_ratings_link, backref='books') | ||||
|     languages = relationship(Languages, secondary=books_languages_link, backref='books') | ||||
|     publishers = relationship(Publishers, secondary=books_publishers_link, backref='books') | ||||
|     identifiers = relationship(Identifiers, backref='books') | ||||
|  | ||||
|     def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover, | ||||
|                  authors, tags, languages=None): | ||||
| @@ -602,6 +601,33 @@ class CalibreDB(): | ||||
|         return self.session.query(Books).filter(Books.id == book_id). \ | ||||
|             filter(self.common_filters(allow_show_archived)).first() | ||||
|  | ||||
|     def get_book_read_archived(self, book_id, read_column, allow_show_archived=False): | ||||
|         # Add missing relationships for inter database joins | ||||
|         #setattr(Books, "is_archived", | ||||
|         #        relationship(ub.ArchivedBook, | ||||
|         #                     uselist=False, | ||||
|         #                     foreign_keys=ub.ArchivedBook.book_id, | ||||
|         #                     primaryjoin=and_(Books.id == ub.ArchivedBook.book_id, | ||||
|         #                                      int(current_user.id) == ub.ArchivedBook.user_id))) | ||||
|         if not read_column: | ||||
|             bd = (self.session.query(Books, ub.ReadBook.read_status, ub.ArchivedBook.is_archived).select_from(Books) | ||||
|                   .join(ub.ReadBook, and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id), | ||||
|                   isouter=True)) | ||||
|         else: | ||||
|             try: | ||||
|                 read_column = cc_classes[read_column] | ||||
|                 bd = (self.session.query(Books, read_column.value, ub.ArchivedBook.is_archived).select_from(Books) | ||||
|                       .join(read_column, read_column.book == book_id, | ||||
|                       isouter=True)) | ||||
|             except (KeyError, AttributeError): | ||||
|                 log.error("Custom Column No.%d is not existing in calibre database", read_column) | ||||
|                 # Skip linking read column and return None instead of read status | ||||
|                 bd = self.session.query(Books, None, ub.ArchivedBook.is_archived) | ||||
|         return (bd.filter(Books.id == book_id) | ||||
|                 .join(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id, | ||||
|                                             int(current_user.id) == ub.ArchivedBook.user_id), isouter=True) | ||||
|                 .filter(self.common_filters(allow_show_archived)).first()) | ||||
|  | ||||
|     def get_book_by_uuid(self, book_uuid): | ||||
|         return self.session.query(Books).filter(Books.uuid == book_uuid).first() | ||||
|  | ||||
| @@ -709,8 +735,6 @@ class CalibreDB(): | ||||
|             entries = query.order_by(*order).offset(off).limit(pagesize).all() | ||||
|         except Exception as ex: | ||||
|             log.debug_or_exception(ex) | ||||
|         #for book in entries: | ||||
|         #    book = self.order_authors(book) | ||||
|         return entries, randm, pagination | ||||
|  | ||||
|     # Orders all Authors in the list according to authors sort | ||||
| @@ -730,7 +754,7 @@ class CalibreDB(): | ||||
|                     authors_ordered.append(r) | ||||
|         if not error: | ||||
|             entry.authors = authors_ordered | ||||
|         return entry | ||||
|         return authors_ordered | ||||
|  | ||||
|     def get_typeahead(self, database, query, replace=('', ''), tag_filter=true()): | ||||
|         query = query or '' | ||||
|   | ||||
| @@ -376,7 +376,7 @@ def render_edit_book(book_id): | ||||
|     for lang in book.languages: | ||||
|         lang.language_name = isoLanguages.get_language_name(get_locale(), lang.lang_code) | ||||
|  | ||||
|     book = calibre_db.order_authors(book) | ||||
|     book.authors = calibre_db.order_authors(book) | ||||
|  | ||||
|     author_names = [] | ||||
|     for authr in book.authors: | ||||
| @@ -1249,9 +1249,9 @@ def table_xchange_author_title(): | ||||
|             modif_date = False | ||||
|             book = calibre_db.get_book(val) | ||||
|             authors = book.title | ||||
|             entries = calibre_db.order_authors(book) | ||||
|             book.authors = calibre_db.order_authors(book) | ||||
|             author_names = [] | ||||
|             for authr in entries.authors: | ||||
|             for authr in book.authors: | ||||
|                 author_names.append(authr.name.replace('|', ',')) | ||||
|  | ||||
|             title_change = handle_title_on_edit(book, " ".join(author_names)) | ||||
|   | ||||
| @@ -36,9 +36,9 @@ | ||||
|             </div> | ||||
|             {% endif %} | ||||
|           {% endif %} | ||||
|             {% if g.user.kindle_mail and kindle_list %} | ||||
|               {% if kindle_list.__len__() == 1 %} | ||||
|                 <a href="{{url_for('web.send_to_kindle', book_id=entry.id, book_format=kindle_list[0]['format'], convert=kindle_list[0]['convert'])}}" id="sendbtn" data-text="{{_('Send to Kindle')}}" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-send"></span> {{kindle_list[0]['text']}}</a> | ||||
|             {% if g.user.kindle_mail and entry.kindle_list %} | ||||
|               {% if entry.kindle_list.__len__() == 1 %} | ||||
|                 <a href="{{url_for('web.send_to_kindle', book_id=entry.id, book_format=entry.kindle_list[0]['format'], convert=entry.kindle_list[0]['convert'])}}" id="sendbtn" data-text="{{_('Send to Kindle')}}" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-send"></span> {{entry.kindle_list[0]['text']}}</a> | ||||
|               {% else %} | ||||
|                 <div class="btn-group" role="group"> | ||||
|                   <button id="sendbtn2" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | ||||
| @@ -46,52 +46,52 @@ | ||||
|                     <span class="caret"></span> | ||||
|                   </button> | ||||
|                     <ul class="dropdown-menu" aria-labelledby="send-to-kindle"> | ||||
|                     {% for format in kindle_list %} | ||||
|                     {% for format in entry.kindle_list %} | ||||
|                       <li><a href="{{url_for('web.send_to_kindle', book_id=entry.id, book_format=format['format'], convert=format['convert'])}}">{{format['text']}}</a></li> | ||||
|                     {%endfor%} | ||||
|                     </ul> | ||||
|                 </div> | ||||
|               {% endif %} | ||||
|             {% endif %} | ||||
|           {% if reader_list and g.user.role_viewer() %} | ||||
|           {% if entry.reader_list and g.user.role_viewer() %} | ||||
|               <div class="btn-group" role="group"> | ||||
|               {% if reader_list|length > 1 %} | ||||
|               {% if entry.reader_list|length > 1 %} | ||||
|                 <button id="read-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | ||||
|                   <span class="glyphicon glyphicon-book"></span> {{_('Read in Browser')}} | ||||
|                   <span class="caret"></span> | ||||
|                 </button> | ||||
|                     <ul class="dropdown-menu" aria-labelledby="read-in-browser"> | ||||
|                     {% for format in reader_list %} | ||||
|                     {% for format in entry.reader_list %} | ||||
|                       <li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{format}}</a></li> | ||||
|                     {%endfor%} | ||||
|                     </ul> | ||||
|                 {% else %} | ||||
|                   <a target="_blank" href="{{url_for('web.read_book', book_id=entry.id, book_format=reader_list[0])}}" id="readbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-book"></span> {{_('Read in Browser')}} - {{reader_list[0]}}</a> | ||||
|                   <a target="_blank" href="{{url_for('web.read_book', book_id=entry.id, book_format=entry.reader_list[0])}}" id="readbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-book"></span> {{_('Read in Browser')}} - {{entry.reader_list[0]}}</a> | ||||
|                 {% endif %} | ||||
|               </div> | ||||
|             {% endif %} | ||||
|             {% if audioentries|length > 0 and g.user.role_viewer() %} | ||||
|             {% if entry.audioentries|length > 0 and g.user.role_viewer() %} | ||||
|               <div class="btn-group" role="group"> | ||||
|               {% if audioentries|length > 1 %} | ||||
|               {% if entry.audioentries|length > 1 %} | ||||
|                 <button id="listen-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | ||||
|                   <span class="glyphicon glyphicon-music"></span> {{_('Listen in Browser')}} | ||||
|                   <span class="caret"></span> | ||||
|                 </button> | ||||
|                     <ul class="dropdown-menu" aria-labelledby="listen-in-browser"> | ||||
|                     {% for format in reader_list %} | ||||
|                     {% for format in entry.reader_list %} | ||||
|                       <li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{format}}</a></li> | ||||
|                     {%endfor%} | ||||
|                     </ul> | ||||
|                   <ul class="dropdown-menu" aria-labelledby="listen-in-browser"> | ||||
|  | ||||
|               {% for format in entry.data %} | ||||
|                   {% if format.format|lower in audioentries %} | ||||
|                   {% if format.format|lower in entry.audioentries %} | ||||
|                     <li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format.format|lower) }}">{{format.format|lower }}</a></li> | ||||
|                     {% endif %} | ||||
|               {% endfor %} | ||||
|                   </ul> | ||||
|                 {% else %} | ||||
|                   <a target="_blank" href="{{url_for('web.read_book', book_id=entry.id, book_format=audioentries[0])}}" id="listenbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-music"></span> {{_('Listen in Browser')}} - {{audioentries[0]}}</a> | ||||
|                   <a target="_blank" href="{{url_for('web.read_book', book_id=entry.id, book_format=entry.audioentries[0])}}" id="listenbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-music"></span> {{_('Listen in Browser')}} - {{entry.audioentries[0]}}</a> | ||||
|                 {% endif %} | ||||
|               </div> | ||||
|             {% endif %} | ||||
| @@ -216,7 +216,7 @@ | ||||
|           <form id="have_read_form" action="{{ url_for('web.toggle_read', book_id=entry.id)}}" method="POST"> | ||||
|             <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> | ||||
|             <label class="block-label"> | ||||
|               <input id="have_read_cb" data-checked="{{_('Mark As Unread')}}" data-unchecked="{{_('Mark As Read')}}" type="checkbox" {% if have_read %}checked{% endif %} > | ||||
|               <input id="have_read_cb" data-checked="{{_('Mark As Unread')}}" data-unchecked="{{_('Mark As Read')}}" type="checkbox" {% if entry.read_status %}checked{% endif %} > | ||||
|               <span>{{_('Read')}}</span> | ||||
|             </label> | ||||
|           </form> | ||||
| @@ -226,7 +226,7 @@ | ||||
|             <form id="archived_form" action="{{ url_for('web.toggle_archived', book_id=entry.id)}}" method="POST"> | ||||
|               <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> | ||||
|               <label class="block-label"> | ||||
|                 <input id="archived_cb" data-checked="{{_('Restore from archive')}}" data-unchecked="{{_('Add to archive')}}" type="checkbox" {% if is_archived %}checked{% endif %} > | ||||
|                 <input id="archived_cb" data-checked="{{_('Restore from archive')}}" data-unchecked="{{_('Add to archive')}}" type="checkbox" {% if entry.is_archived.is_archived %}checked{% endif %} > | ||||
|                 <span>{{_('Archived')}}</span> | ||||
|               </label> | ||||
|             </form> | ||||
|   | ||||
							
								
								
									
										63
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -187,7 +187,7 @@ def toggle_read(book_id): | ||||
|             return "Custom Column No.{} is not existing in calibre database".format(config.config_read_column), 400 | ||||
|         except (OperationalError, InvalidRequestError) as e: | ||||
|             calibre_db.session.rollback() | ||||
|             log.error(u"Read status could not set: %e", e) | ||||
|             log.error(u"Read status could not set: {}".format(e)) | ||||
|             return "Read status could not set: {}".format(e), 400 | ||||
|     return "" | ||||
|  | ||||
| @@ -1756,63 +1756,40 @@ def read_book(book_id, book_format): | ||||
| @web.route("/book/<int:book_id>") | ||||
| @login_required_if_no_ano | ||||
| def show_book(book_id): | ||||
|     entries = calibre_db.get_filtered_book(book_id, allow_show_archived=True) | ||||
|     entries = calibre_db.get_book_read_archived(book_id, config.config_read_column, allow_show_archived=True) | ||||
|     if entries: | ||||
|         for index in range(0, len(entries.languages)): | ||||
|             entries.languages[index].language_name = isoLanguages.get_language_name(get_locale(), entries.languages[ | ||||
|         read_book = entries[1] | ||||
|         archived_book = entries[2] | ||||
|         entry = entries[0] | ||||
|         entry.read_status = read_book == ub.ReadBook.STATUS_FINISHED | ||||
|         entry.is_archived = archived_book | ||||
|         for index in range(0, len(entry.languages)): | ||||
|             entry.languages[index].language_name = isoLanguages.get_language_name(get_locale(), entry.languages[ | ||||
|                 index].lang_code) | ||||
|         cc = get_cc_columns(filter_config_custom_read=True) | ||||
|         book_in_shelfs = [] | ||||
|         shelfs = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).all() | ||||
|         for entry in shelfs: | ||||
|             book_in_shelfs.append(entry.shelf) | ||||
|         for sh in shelfs: | ||||
|             book_in_shelfs.append(sh.shelf) | ||||
|  | ||||
|         if not current_user.is_anonymous: | ||||
|             if not config.config_read_column: | ||||
|                 matching_have_read_book = ub.session.query(ub.ReadBook). \ | ||||
|                     filter(and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id)).all() | ||||
|                 have_read = len( | ||||
|                     matching_have_read_book) > 0 and matching_have_read_book[0].read_status == ub.ReadBook.STATUS_FINISHED | ||||
|             else: | ||||
|                 try: | ||||
|                     matching_have_read_book = getattr(entries, 'custom_column_' + str(config.config_read_column)) | ||||
|                     have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value | ||||
|                 except (KeyError, AttributeError): | ||||
|                     log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column) | ||||
|                     have_read = None | ||||
|         entry.tags = sort(entry.tags, key=lambda tag: tag.name) | ||||
|  | ||||
|             archived_book = ub.session.query(ub.ArchivedBook).\ | ||||
|                 filter(and_(ub.ArchivedBook.user_id == int(current_user.id), | ||||
|                             ub.ArchivedBook.book_id == book_id)).first() | ||||
|             is_archived = archived_book and archived_book.is_archived | ||||
|         entry.authors = calibre_db.order_authors(entry) | ||||
|  | ||||
|         else: | ||||
|             have_read = None | ||||
|             is_archived = None | ||||
|         entry.kindle_list = check_send_to_kindle(entry) | ||||
|         entry.reader_list = check_read_formats(entry) | ||||
|  | ||||
|         entries.tags = sort(entries.tags, key=lambda tag: tag.name) | ||||
|  | ||||
|         entries = calibre_db.order_authors(entries) | ||||
|  | ||||
|         kindle_list = check_send_to_kindle(entries) | ||||
|         reader_list = check_read_formats(entries) | ||||
|  | ||||
|         audioentries = [] | ||||
|         for media_format in entries.data: | ||||
|         entry.audioentries = [] | ||||
|         for media_format in entry.data: | ||||
|             if media_format.format.lower() in constants.EXTENSIONS_AUDIO: | ||||
|                 audioentries.append(media_format.format.lower()) | ||||
|                 entry.audioentries.append(media_format.format.lower()) | ||||
|  | ||||
|         return render_title_template('detail.html', | ||||
|                                      entry=entries, | ||||
|                                      audioentries=audioentries, | ||||
|                                      entry=entry, | ||||
|                                      cc=cc, | ||||
|                                      is_xhr=request.headers.get('X-Requested-With')=='XMLHttpRequest', | ||||
|                                      title=entries.title, | ||||
|                                      title=entry.title, | ||||
|                                      books_shelfs=book_in_shelfs, | ||||
|                                      have_read=have_read, | ||||
|                                      is_archived=is_archived, | ||||
|                                      kindle_list=kindle_list, | ||||
|                                      reader_list=reader_list, | ||||
|                                      page="book") | ||||
|     else: | ||||
|         log.debug(u"Oops! Selected book title is unavailable. File does not exist or is not accessible") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ozzie Isaacs
					Ozzie Isaacs