mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-31 15:23:02 +00:00 
			
		
		
		
	make pretty filenames for downloads; remove random books section on most pages
This commit is contained in:
		| @@ -155,6 +155,7 @@ class Books(Base): | ||||
| 	id = Column(Integer,primary_key=True) | ||||
| 	title = Column(String) | ||||
| 	sort = Column(String) | ||||
| 	author_sort = Column(String) | ||||
| 	timestamp = Column(String) | ||||
| 	pubdate = Column(String) | ||||
| 	series_index = Column(String) | ||||
| @@ -170,9 +171,10 @@ class Books(Base): | ||||
| 	ratings = relationship('Ratings', secondary=books_ratings_link, backref='books') | ||||
| 	languages = relationship('Languages', secondary=books_languages_link, backref='books') | ||||
|  | ||||
| 	def __init__(self, title, sort, timestamp, pubdate, series_index, last_modified, path, has_cover, authors, tags): | ||||
| 	def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover, authors, tags): | ||||
| 		self.title = title | ||||
| 		self.sort = sort | ||||
| 		self.author_sort = author_sort | ||||
| 		self.timestamp = timestamp | ||||
| 		self.pubdate = pubdate | ||||
| 		self.series_index = series_index | ||||
| @@ -181,11 +183,8 @@ class Books(Base): | ||||
| 		self.has_cover = has_cover | ||||
| 		self.tags = tags | ||||
|  | ||||
|  | ||||
| 	def __repr__(self): | ||||
| 		return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}')>".format(self.title, self.sort, self.timestamp, self.pubdate, self.series_index, self.last_modified ,self.path, self.has_cover) | ||||
|  | ||||
|  | ||||
| 		return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}{8}')>".format(self.title, self.sort, self.author_sort, self.timestamp, self.pubdate, self.series_index, self.last_modified ,self.path, self.has_cover) | ||||
|  | ||||
| Base.metadata.create_all(engine) | ||||
| Session = sessionmaker() | ||||
|   | ||||
| @@ -8,6 +8,8 @@ import smtplib | ||||
| import sys | ||||
| import os | ||||
| import traceback | ||||
| import re | ||||
| import unicodedata | ||||
| from StringIO import StringIO | ||||
| from email import encoders | ||||
| from email.MIMEBase import MIMEBase | ||||
| @@ -125,3 +127,25 @@ def get_attachment(file_path): | ||||
|         message = ('The requested file could not be read. Maybe wrong ' | ||||
|                    'permissions?') | ||||
|         return None | ||||
|  | ||||
| def get_valid_filename(value): | ||||
|     """ | ||||
|     Returns the given string converted to a string that can be used for a clean | ||||
|     filename. Limits num characters to 128 max. | ||||
|     """ | ||||
|     value = value[:128] | ||||
|     re_slugify = re.compile('[^\w\s-]', re.UNICODE) | ||||
|     value = unicodedata.normalize('NFKD', value) | ||||
|     re_slugify = re.compile('[^\w\s-]', re.UNICODE) | ||||
|     value = unicode(re_slugify.sub('', value).strip()) | ||||
|     value = re.sub('[\s]+', '_', value, flags=re.U) | ||||
|     return value | ||||
|  | ||||
| def get_normalized_author(value): | ||||
|     """ | ||||
|     Normalizes sorted author name | ||||
|     """ | ||||
|     value = unicodedata.normalize('NFKD', value) | ||||
|     value = re.sub('[^\w,\s]', '', value, flags=re.U) | ||||
|     value = " ".join(value.split(", ")[::-1]) | ||||
|     return value | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| {% extends "layout.html" %} | ||||
| {% block body %} | ||||
| {% if random.count() > 0 %} | ||||
| <div class="discover"> | ||||
|   <h2>Discover (Random Books)</h2> | ||||
|   <div class="row"> | ||||
| @@ -34,6 +35,7 @@ | ||||
|     {% endfor %} | ||||
|   </div> | ||||
| </div> | ||||
| {% endif %} | ||||
| <div class="discover load-more"> | ||||
|   <h2>{{title}}</h2> | ||||
|   <div class="row"> | ||||
|   | ||||
							
								
								
									
										36
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -7,6 +7,7 @@ from flask import Flask, render_template, session, request, Response, redirect, | ||||
| from cps import db, config, ub, helper | ||||
| import os | ||||
| from sqlalchemy.sql.expression import func | ||||
| from sqlalchemy.sql.expression import false | ||||
| from sqlalchemy.exc import IntegrityError | ||||
| from math import ceil | ||||
| from flask.ext.login import LoginManager, login_user, logout_user, login_required, current_user | ||||
| @@ -15,6 +16,7 @@ import requests, zipfile | ||||
| from werkzeug.security import generate_password_hash, check_password_hash | ||||
| from functools import wraps | ||||
| import base64 | ||||
| from sqlalchemy.sql import * | ||||
|  | ||||
| app = (Flask(__name__)) | ||||
|  | ||||
| @@ -179,7 +181,7 @@ def feed_discover(): | ||||
|         entries = db.session.query(db.Books).order_by(func.random()).limit(config.NEWEST_BOOKS) | ||||
|         off = 0 | ||||
|     xml = render_template('feed.xml', entries=entries, next_url="/feed/discover?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off))) | ||||
|     response= make_response(xml) | ||||
|     response = make_response(xml) | ||||
|     response.headers["Content-Type"] = "application/xml" | ||||
|     return response | ||||
|  | ||||
| @@ -204,8 +206,13 @@ def get_opds_download_link(book_id, format): | ||||
|     book = db.session.query(db.Books).filter(db.Books.id == book_id).first() | ||||
|     data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == format.upper()).first() | ||||
|     helper.update_download(book_id, int(current_user.id)) | ||||
|     author = helper.get_normalized_author(book.author_sort) | ||||
|     file_name = book.title | ||||
|     if len(author) > 0: | ||||
|         file_name = author+'-'+file_name | ||||
|     file_name = helper.get_valid_filename(file_name) | ||||
|     response = make_response(send_from_directory(os.path.join(config.DB_ROOT, book.path), data.name + "." +format)) | ||||
|     response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (data.name, format) | ||||
|     response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (file_name, format) | ||||
|     return response | ||||
|  | ||||
| @app.route("/", defaults={'page': 1}) | ||||
| @@ -223,7 +230,7 @@ def index(page): | ||||
| @app.route("/hot", defaults={'page': 1}) | ||||
| @app.route('/hot/page/<int:page>') | ||||
| def hot_books(page): | ||||
|     random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS) | ||||
|     random = db.session.query(db.Books).filter(false()) | ||||
|     # if page == 1: | ||||
|     #     entries = db.session.query(db.Books).filter(db.Books.ratings.any(db.Ratings.rating > 9)).order_by(db.Books.last_modified.desc()).limit(config.NEWEST_BOOKS) | ||||
|     # else: | ||||
| @@ -236,9 +243,13 @@ def hot_books(page): | ||||
|     entries = list() | ||||
|     for book in hot_books: | ||||
|         entries.append(db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()) | ||||
|  | ||||
|     pagination = Pagination(page, config.NEWEST_BOOKS, len(all_books.all())) | ||||
|     return render_template('index.html', random=random, entries=entries, pagination=pagination, title="Hot Books (most downloaded)") | ||||
|     numBooks = len(all_books.all()) | ||||
|     pages = int(ceil(numBooks / float(config.NEWEST_BOOKS))) | ||||
|     if pages > 1: | ||||
|         pagination = Pagination(page, config.NEWEST_BOOKS, len(all_books.all())) | ||||
|         return render_template('index.html', random=random, entries=entries, pagination=pagination, title="Hot Books (most downloaded)") | ||||
|     else: | ||||
|         return render_template('index.html', random=random, entries=entries, title="Hot Books (most downloaded)") | ||||
|  | ||||
| @app.route("/stats") | ||||
| def stats(): | ||||
| @@ -272,7 +283,7 @@ def category_list(): | ||||
|  | ||||
| @app.route("/category/<name>") | ||||
| def category(name): | ||||
|     random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS) | ||||
|     random = db.session.query(db.Books).filter(false()) | ||||
|     if name != "all": | ||||
|         entries = db.session.query(db.Books).filter(db.Books.tags.any(db.Tags.name.like("%" +name + "%" ))).order_by(db.Books.last_modified.desc()).all() | ||||
|     else: | ||||
| @@ -281,7 +292,7 @@ def category(name): | ||||
|  | ||||
| @app.route("/series/<name>") | ||||
| def series(name): | ||||
|     random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS) | ||||
|     random = db.session.query(db.Books).filter(false()) | ||||
|     entries = db.session.query(db.Books).filter(db.Books.series.any(db.Series.name.like("%" +name + "%" ))).order_by(db.Books.series_index).all() | ||||
|     return render_template('index.html', random=random, entries=entries, title="Series: %s" % name) | ||||
|  | ||||
| @@ -309,7 +320,7 @@ def author_list(): | ||||
|  | ||||
| @app.route("/author/<name>") | ||||
| def author(name): | ||||
|     random = db.session.query(db.Books).order_by(func.random()).limit(config.RANDOM_BOOKS) | ||||
|     random = db.session.query(db.Books).filter(false()) | ||||
|     entries = db.session.query(db.Books).filter(db.Books.authors.any(db.Authors.name.like("%" +  name + "%"))).all() | ||||
|     return render_template('index.html', random=random, entries=entries, title="Author: %s" % name) | ||||
|  | ||||
| @@ -346,8 +357,13 @@ def get_download_link(book_id, format): | ||||
|     book = db.session.query(db.Books).filter(db.Books.id == book_id).first() | ||||
|     data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == format.upper()).first() | ||||
|     helper.update_download(book_id, int(current_user.id)) | ||||
|     author = helper.get_normalized_author(book.author_sort) | ||||
|     file_name = book.title | ||||
|     if len(author) > 0: | ||||
|         file_name = author+'-'+file_name | ||||
|     file_name = helper.get_valid_filename(file_name) | ||||
|     response = make_response(send_from_directory(os.path.join(config.DB_ROOT, book.path), data.name + "." +format)) | ||||
|     response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (data.name, format) | ||||
|     response.headers["Content-Disposition"] = "attachment; filename=%s.%s" % (file_name, format) | ||||
|     return response | ||||
|  | ||||
| @app.route('/register', methods = ['GET', 'POST']) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jan Broer
					Jan Broer