make pretty filenames for downloads; remove random books section on most pages
This commit is contained in:
parent
2b846b1e6b
commit
f163ef2202
|
@ -155,6 +155,7 @@ class Books(Base):
|
||||||
id = Column(Integer,primary_key=True)
|
id = Column(Integer,primary_key=True)
|
||||||
title = Column(String)
|
title = Column(String)
|
||||||
sort = Column(String)
|
sort = Column(String)
|
||||||
|
author_sort = Column(String)
|
||||||
timestamp = Column(String)
|
timestamp = Column(String)
|
||||||
pubdate = Column(String)
|
pubdate = Column(String)
|
||||||
series_index = Column(String)
|
series_index = Column(String)
|
||||||
|
@ -170,9 +171,10 @@ class Books(Base):
|
||||||
ratings = relationship('Ratings', secondary=books_ratings_link, backref='books')
|
ratings = relationship('Ratings', secondary=books_ratings_link, backref='books')
|
||||||
languages = relationship('Languages', secondary=books_languages_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.title = title
|
||||||
self.sort = sort
|
self.sort = sort
|
||||||
|
self.author_sort = author_sort
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.pubdate = pubdate
|
self.pubdate = pubdate
|
||||||
self.series_index = series_index
|
self.series_index = series_index
|
||||||
|
@ -181,11 +183,8 @@ class Books(Base):
|
||||||
self.has_cover = has_cover
|
self.has_cover = has_cover
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
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)
|
Base.metadata.create_all(engine)
|
||||||
Session = sessionmaker()
|
Session = sessionmaker()
|
||||||
|
|
|
@ -8,6 +8,8 @@ import smtplib
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from email import encoders
|
from email import encoders
|
||||||
from email.MIMEBase import MIMEBase
|
from email.MIMEBase import MIMEBase
|
||||||
|
@ -125,3 +127,25 @@ def get_attachment(file_path):
|
||||||
message = ('The requested file could not be read. Maybe wrong '
|
message = ('The requested file could not be read. Maybe wrong '
|
||||||
'permissions?')
|
'permissions?')
|
||||||
return None
|
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" %}
|
{% extends "layout.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
{% if random.count() > 0 %}
|
||||||
<div class="discover">
|
<div class="discover">
|
||||||
<h2>Discover (Random Books)</h2>
|
<h2>Discover (Random Books)</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="discover load-more">
|
<div class="discover load-more">
|
||||||
<h2>{{title}}</h2>
|
<h2>{{title}}</h2>
|
||||||
<div class="row">
|
<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
|
from cps import db, config, ub, helper
|
||||||
import os
|
import os
|
||||||
from sqlalchemy.sql.expression import func
|
from sqlalchemy.sql.expression import func
|
||||||
|
from sqlalchemy.sql.expression import false
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from flask.ext.login import LoginManager, login_user, logout_user, login_required, current_user
|
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 werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import base64
|
import base64
|
||||||
|
from sqlalchemy.sql import *
|
||||||
|
|
||||||
app = (Flask(__name__))
|
app = (Flask(__name__))
|
||||||
|
|
||||||
|
@ -179,7 +181,7 @@ def feed_discover():
|
||||||
entries = db.session.query(db.Books).order_by(func.random()).limit(config.NEWEST_BOOKS)
|
entries = db.session.query(db.Books).order_by(func.random()).limit(config.NEWEST_BOOKS)
|
||||||
off = 0
|
off = 0
|
||||||
xml = render_template('feed.xml', entries=entries, next_url="/feed/discover?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
|
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"
|
response.headers["Content-Type"] = "application/xml"
|
||||||
return response
|
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()
|
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()
|
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))
|
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 = 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
|
return response
|
||||||
|
|
||||||
@app.route("/", defaults={'page': 1})
|
@app.route("/", defaults={'page': 1})
|
||||||
|
@ -223,7 +230,7 @@ def index(page):
|
||||||
@app.route("/hot", defaults={'page': 1})
|
@app.route("/hot", defaults={'page': 1})
|
||||||
@app.route('/hot/page/<int:page>')
|
@app.route('/hot/page/<int:page>')
|
||||||
def hot_books(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:
|
# 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)
|
# 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:
|
# else:
|
||||||
|
@ -236,9 +243,13 @@ def hot_books(page):
|
||||||
entries = list()
|
entries = list()
|
||||||
for book in hot_books:
|
for book in hot_books:
|
||||||
entries.append(db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first())
|
entries.append(db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first())
|
||||||
|
numBooks = len(all_books.all())
|
||||||
pagination = Pagination(page, config.NEWEST_BOOKS, len(all_books.all()))
|
pages = int(ceil(numBooks / float(config.NEWEST_BOOKS)))
|
||||||
return render_template('index.html', random=random, entries=entries, pagination=pagination, title="Hot Books (most downloaded)")
|
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")
|
@app.route("/stats")
|
||||||
def stats():
|
def stats():
|
||||||
|
@ -272,7 +283,7 @@ def category_list():
|
||||||
|
|
||||||
@app.route("/category/<name>")
|
@app.route("/category/<name>")
|
||||||
def 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":
|
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()
|
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:
|
else:
|
||||||
|
@ -281,7 +292,7 @@ def category(name):
|
||||||
|
|
||||||
@app.route("/series/<name>")
|
@app.route("/series/<name>")
|
||||||
def 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()
|
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)
|
return render_template('index.html', random=random, entries=entries, title="Series: %s" % name)
|
||||||
|
|
||||||
|
@ -309,7 +320,7 @@ def author_list():
|
||||||
|
|
||||||
@app.route("/author/<name>")
|
@app.route("/author/<name>")
|
||||||
def 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()
|
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)
|
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()
|
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()
|
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))
|
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 = 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
|
return response
|
||||||
|
|
||||||
@app.route('/register', methods = ['GET', 'POST'])
|
@app.route('/register', methods = ['GET', 'POST'])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user