Fixes for Kobo sync
Better output on upload cover Fix for download after access to opds/fileformat Fix osd search link Added ratings to opds feed Change for kobo sync for testing
This commit is contained in:
parent
fb83bfb363
commit
d267338837
7 changed files with 88 additions and 60 deletions
|
@ -369,11 +369,11 @@ def upload_cover(request, book):
|
|||
requested_file = request.files['btn-upload-cover']
|
||||
# check for empty request
|
||||
if requested_file.filename != '':
|
||||
if helper.save_cover(requested_file, book.path) is True:
|
||||
ret, message = helper.save_cover(requested_file, book.path)
|
||||
if ret is True:
|
||||
return True
|
||||
else:
|
||||
# ToDo Message not always coorect
|
||||
flash(_(u"Cover is not a supported imageformat (jpg/png/webp), can't save"), category="error")
|
||||
flash(message, category="error")
|
||||
return False
|
||||
return None
|
||||
|
||||
|
|
|
@ -508,16 +508,16 @@ def save_cover_from_filestorage(filepath, saved_filename, img):
|
|||
os.makedirs(filepath)
|
||||
except OSError:
|
||||
log.error(u"Failed to create path for cover")
|
||||
return False
|
||||
return False, _(u"Failed to create path for cover")
|
||||
try:
|
||||
img.save(os.path.join(filepath, saved_filename))
|
||||
except IOError:
|
||||
log.error(u"Cover-file is not a valid image file")
|
||||
return False
|
||||
return False, _(u"Cover-file is not a valid image file")
|
||||
except OSError:
|
||||
log.error(u"Failed to store cover-file")
|
||||
return False
|
||||
return True
|
||||
return False, _(u"Failed to store cover-file")
|
||||
return True, None
|
||||
|
||||
|
||||
# saves book cover to gdrive or locally
|
||||
|
@ -527,7 +527,7 @@ def save_cover(img, book_path):
|
|||
if use_PIL:
|
||||
if content_type not in ('image/jpeg', 'image/png', 'image/webp'):
|
||||
log.error("Only jpg/jpeg/png/webp files are supported as coverfile")
|
||||
return False
|
||||
return False, _("Only jpg/jpeg/png/webp files are supported as coverfile")
|
||||
# convert to jpg because calibre only supports jpg
|
||||
if content_type in ('image/png', 'image/webp'):
|
||||
if hasattr(img,'stream'):
|
||||
|
@ -541,17 +541,18 @@ def save_cover(img, book_path):
|
|||
else:
|
||||
if content_type not in ('image/jpeg'):
|
||||
log.error("Only jpg/jpeg files are supported as coverfile")
|
||||
return False
|
||||
return False, _("Only jpg/jpeg files are supported as coverfile")
|
||||
|
||||
if config.config_use_google_drive:
|
||||
tmpDir = gettempdir()
|
||||
if save_cover_from_filestorage(tmpDir, "uploaded_cover.jpg", img) is True:
|
||||
ret, message = save_cover_from_filestorage(tmpDir, "uploaded_cover.jpg", img)
|
||||
if ret is True:
|
||||
gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'),
|
||||
os.path.join(tmpDir, "uploaded_cover.jpg"))
|
||||
log.info("Cover is saved on Google Drive")
|
||||
return True
|
||||
return True, None
|
||||
else:
|
||||
return False
|
||||
return False, message
|
||||
else:
|
||||
return save_cover_from_filestorage(os.path.join(config.config_calibre_dir, book_path), "cover.jpg", img)
|
||||
|
||||
|
@ -818,11 +819,11 @@ def get_download_link(book_id, book_format):
|
|||
book_format = book_format.split(".")[0]
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
|
||||
if book:
|
||||
data = db.session.query(db.Data).filter(db.Data.book == book.id)\
|
||||
data1 = db.session.query(db.Data).filter(db.Data.book == book.id)\
|
||||
.filter(db.Data.format == book_format.upper()).first()
|
||||
else:
|
||||
abort(404)
|
||||
if data:
|
||||
if data1:
|
||||
# collect downloaded books only for registered user and not for anonymous user
|
||||
if current_user.is_authenticated:
|
||||
ub.update_download(book_id, int(current_user.id))
|
||||
|
@ -834,7 +835,7 @@ def get_download_link(book_id, book_format):
|
|||
headers["Content-Type"] = mimetypes.types_map.get('.' + book_format, "application/octet-stream")
|
||||
headers["Content-Disposition"] = "attachment; filename=%s.%s; filename*=UTF-8''%s.%s" % (
|
||||
quote(file_name.encode('utf-8')), book_format, quote(file_name.encode('utf-8')), book_format)
|
||||
return do_download_file(book, book_format, data, headers)
|
||||
return do_download_file(book, book_format, data1, headers)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
|
46
cps/kobo.py
46
cps/kobo.py
|
@ -214,29 +214,19 @@ def HandleMetadataRequest(book_uuid):
|
|||
|
||||
def get_download_url_for_book(book, book_format):
|
||||
if not current_app.wsgi_app.is_proxied:
|
||||
if request.environ['SERVER_NAME'] != '::':
|
||||
return "{url_scheme}://{url_base}:{url_port}/download/{book_id}/{book_format}".format(
|
||||
url_scheme=request.environ['wsgi.url_scheme'],
|
||||
url_base=request.environ['SERVER_NAME'],
|
||||
url_port=config.config_port,
|
||||
book_id=book.id,
|
||||
book_format=book_format.lower()
|
||||
)
|
||||
else:
|
||||
return "{url_scheme}://{url_base}:{url_port}/download/{book_id}/{book_format}".format(
|
||||
url_scheme=request.environ['wsgi.url_scheme'],
|
||||
url_base=request.host, # ToDo: both server ??
|
||||
url_port=config.config_port,
|
||||
book_id=book.id,
|
||||
book_format=book_format.lower()
|
||||
)
|
||||
else:
|
||||
return url_for(
|
||||
"web.download_link",
|
||||
return "{url_scheme}://{url_base}:{url_port}/download/{book_id}/{book_format}".format(
|
||||
url_scheme=request.scheme,
|
||||
url_base=request.host,
|
||||
url_port=config.config_port,
|
||||
book_id=book.id,
|
||||
book_format=book_format.lower(),
|
||||
_external=True,
|
||||
book_format=book_format.lower()
|
||||
)
|
||||
return url_for(
|
||||
"web.download_link",
|
||||
book_id=book.id,
|
||||
book_format=book_format.lower(),
|
||||
_external=True,
|
||||
)
|
||||
|
||||
|
||||
def create_book_entitlement(book):
|
||||
|
@ -466,15 +456,11 @@ def HandleInitRequest():
|
|||
|
||||
if not current_app.wsgi_app.is_proxied:
|
||||
log.debug('Kobo: Received unproxied request, changed request port to server port')
|
||||
if request.environ['SERVER_NAME'] != '::':
|
||||
calibre_web_url = "{url_scheme}://{url_base}:{url_port}".format(
|
||||
url_scheme=request.environ['wsgi.url_scheme'],
|
||||
url_base=request.environ['SERVER_NAME'],
|
||||
url_port=config.config_port
|
||||
)
|
||||
else:
|
||||
log.debug('Kobo: Received unproxied request, on IPV6 host')
|
||||
calibre_web_url = url_for("web.index", _external=True).strip("/")
|
||||
calibre_web_url = "{url_scheme}://{url_base}:{url_port}".format(
|
||||
url_scheme=request.scheme,
|
||||
url_base=request.host,
|
||||
url_port=config.config_port
|
||||
)
|
||||
else:
|
||||
calibre_web_url = url_for("web.index", _external=True).strip("/")
|
||||
|
||||
|
|
59
cps/opds.py
59
cps/opds.py
|
@ -56,6 +56,20 @@ def requires_basic_auth_if_no_ano(f):
|
|||
return decorated
|
||||
|
||||
|
||||
class FeedObject():
|
||||
def __init__(self,rating_id , rating_name):
|
||||
self.rating_id = rating_id
|
||||
self.rating_name = rating_name
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.rating_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.rating_name
|
||||
|
||||
|
||||
@opds.route("/opds/")
|
||||
@opds.route("/opds")
|
||||
@requires_basic_auth_if_no_ano
|
||||
|
@ -214,6 +228,31 @@ def feed_series(book_id):
|
|||
db.Books, db.Books.series.any(db.Series.id == book_id), [db.Books.series_index])
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
|
||||
@opds.route("/opds/ratings")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_ratingindex():
|
||||
off = request.args.get("offset") or 0
|
||||
entries = db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'),
|
||||
(db.Ratings.rating / 2).label('name')) \
|
||||
.join(db.books_ratings_link).join(db.Books).filter(common_filters()) \
|
||||
.group_by(text('books_ratings_link.rating')).order_by(db.Ratings.rating).all()
|
||||
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
len(entries))
|
||||
element = list()
|
||||
for entry in entries:
|
||||
element.append(FeedObject(entry[0].id, "{} Stars".format(entry.name)))
|
||||
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_ratings', pagination=pagination)
|
||||
|
||||
@opds.route("/opds/ratings/<book_id>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_ratings(book_id):
|
||||
off = request.args.get("offset") or 0
|
||||
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
||||
db.Books, db.Books.ratings.any(db.Ratings.id == book_id),[db.Books.timestamp.desc()])
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
|
||||
|
||||
@opds.route("/opds/formats")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_formatindex():
|
||||
|
@ -222,10 +261,11 @@ def feed_formatindex():
|
|||
.group_by(db.Data.format).order_by(db.Data.format).all()
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
len(entries))
|
||||
|
||||
element = list()
|
||||
for entry in entries:
|
||||
entry.name = entry.format
|
||||
entry.id = entry.format
|
||||
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_format', pagination=pagination)
|
||||
element.append(FeedObject(entry.format, entry.format))
|
||||
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_format', pagination=pagination)
|
||||
|
||||
|
||||
@opds.route("/opds/formats/<book_id>")
|
||||
|
@ -265,16 +305,9 @@ def feed_languages(book_id):
|
|||
off = request.args.get("offset") or 0
|
||||
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
||||
db.Books, db.Books.languages.any(db.Languages.id == book_id), [db.Books.timestamp.desc()])
|
||||
'''for entry in entries:
|
||||
for index in range(0, len(entry.languages)):
|
||||
try:
|
||||
entry.languages[index].language_name = LC.parse(entry.languages[index].lang_code).get_language_name(
|
||||
get_locale())
|
||||
except UnknownLocaleError:
|
||||
entry.languages[index].language_name = _(
|
||||
isoLanguages.get(part3=entry.languages[index].lang_code).name)'''
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
|
||||
|
||||
@opds.route("/opds/shelfindex", defaults={'public': 0})
|
||||
@opds.route("/opds/shelfindex/<string:public>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
|
@ -319,11 +352,11 @@ def feed_shelf(book_id):
|
|||
@requires_basic_auth_if_no_ano
|
||||
@download_required
|
||||
def opds_download_link(book_id, book_format):
|
||||
return get_download_link(book_id,book_format)
|
||||
return get_download_link(book_id,book_format.lower())
|
||||
|
||||
|
||||
@opds.route("/ajax/book/<string:uuid>/<library>")
|
||||
@opds.route("/ajax/book/<string:uuid>")
|
||||
@opds.route("/ajax/book/<string:uuid>",defaults={'library': ""})
|
||||
@requires_basic_auth_if_no_ano
|
||||
def get_metadata_calibre_companion(uuid, library):
|
||||
entry = db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first()
|
||||
|
|
|
@ -92,6 +92,14 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by Languages')}}</content>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>{{_('Ratings')}}</title>
|
||||
<link href="{{url_for('opds.feed_ratingindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
<id>{{url_for('opds.feed_ratingindex')}}</id>
|
||||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by Rating')}}</content>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>{{_('File formats')}}</title>
|
||||
<link href="{{url_for('opds.feed_formatindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Developer>Janeczku</Developer>
|
||||
<Contact>https://github.com/janeczku/calibre-web</Contact>
|
||||
<Url type="text/html"
|
||||
template="{{url_for('opds.feed_cc_search')}}{searchTerms}"/>
|
||||
template="{{url_for('opds.feed_cc_search')}}/{searchTerms}"/>
|
||||
<Url type="application/atom+xml"
|
||||
template="{{url_for('opds.feed_normal_search')}}?query={searchTerms}"/>
|
||||
<SyndicationRight>open</SyndicationRight>
|
||||
|
|
|
@ -1044,7 +1044,7 @@ def serve_book(book_id, book_format, anyname):
|
|||
@login_required_if_no_ano
|
||||
@download_required
|
||||
def download_link(book_id, book_format):
|
||||
return get_download_link(book_id, book_format)
|
||||
return get_download_link(book_id, book_format.lower())
|
||||
|
||||
|
||||
@web.route('/send/<int:book_id>/<book_format>/<int:convert>')
|
||||
|
|
Loading…
Reference in a new issue