From f163ef2202d9b09c74892d58790f17f89a56e8f0 Mon Sep 17 00:00:00 2001 From: Jan Broer Date: Sat, 26 Mar 2016 16:12:29 +0100 Subject: [PATCH] make pretty filenames for downloads; remove random books section on most pages --- cps/db.py | 9 ++++----- cps/helper.py | 24 ++++++++++++++++++++++++ cps/templates/index.html | 2 ++ cps/web.py | 36 ++++++++++++++++++++++++++---------- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/cps/db.py b/cps/db.py index f5c3ccc9..d4d0381f 100755 --- a/cps/db.py +++ b/cps/db.py @@ -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"".format(self.title, self.sort, self.timestamp, self.pubdate, self.series_index, self.last_modified ,self.path, self.has_cover) - - + return u"".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() diff --git a/cps/helper.py b/cps/helper.py index 64c770ef..caff999a 100755 --- a/cps/helper.py +++ b/cps/helper.py @@ -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 diff --git a/cps/templates/index.html b/cps/templates/index.html index bf0d6932..5b061133 100755 --- a/cps/templates/index.html +++ b/cps/templates/index.html @@ -1,5 +1,6 @@ {% extends "layout.html" %} {% block body %} +{% if random.count() > 0 %}

Discover (Random Books)

@@ -34,6 +35,7 @@ {% endfor %}
+{% endif %}

{{title}}

diff --git a/cps/web.py b/cps/web.py index fe8fd8cb..9eccb581 100755 --- a/cps/web.py +++ b/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/') 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/") 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/") 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/") 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'])