Merge remote-tracking branch 'upstream/master' into jef/download-kobo
This commit is contained in:
commit
711a697570
|
@ -295,15 +295,16 @@ def delete_book_file(book, calibrepath, book_format=None):
|
||||||
return True, None
|
return True, None
|
||||||
else:
|
else:
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
if len(next(os.walk(path))[1]):
|
|
||||||
log.error("Deleting book %s failed, path has subfolders: %s", book.id, book.path)
|
|
||||||
return False , _("Deleting book %(id)s failed, path has subfolders: %(path)s",
|
|
||||||
id=book.id,
|
|
||||||
path=book.path)
|
|
||||||
try:
|
try:
|
||||||
for root, __, files in os.walk(path):
|
for root, folders, files in os.walk(path):
|
||||||
for f in files:
|
for f in files:
|
||||||
os.unlink(os.path.join(root, f))
|
os.unlink(os.path.join(root, f))
|
||||||
|
if len(folders):
|
||||||
|
log.warning("Deleting book {} failed, path {} has subfolders: {}".format(book.id,
|
||||||
|
book.path, folders))
|
||||||
|
return True, _("Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s",
|
||||||
|
id=book.id,
|
||||||
|
path=book.path)
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
log.error("Deleting book %s failed: %s", book.id, e)
|
log.error("Deleting book %s failed: %s", book.id, e)
|
||||||
|
|
27
cps/kobo.py
27
cps/kobo.py
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
import itertools
|
|
||||||
import json
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -318,8 +316,15 @@ def get_description(book):
|
||||||
# TODO handle multiple authors
|
# TODO handle multiple authors
|
||||||
def get_author(book):
|
def get_author(book):
|
||||||
if not book.authors:
|
if not book.authors:
|
||||||
return None
|
return {"Contributors": None}
|
||||||
return book.authors[0].name
|
if len(book.authors) > 1:
|
||||||
|
author_list = []
|
||||||
|
autor_roles = []
|
||||||
|
for author in book.authors:
|
||||||
|
autor_roles.append({"Name":author.name, "Role":"Author"})
|
||||||
|
author_list.append(author.name)
|
||||||
|
return {"ContributorRoles": autor_roles, "Contributors":author_list}
|
||||||
|
return {"ContributorRoles": [{"Name":book.authors[0].name, "Role":"Author"}], "Contributors": book.authors[0].name}
|
||||||
|
|
||||||
|
|
||||||
def get_publisher(book):
|
def get_publisher(book):
|
||||||
|
@ -358,7 +363,7 @@ def get_metadata(book):
|
||||||
book_uuid = book.uuid
|
book_uuid = book.uuid
|
||||||
metadata = {
|
metadata = {
|
||||||
"Categories": ["00000000-0000-0000-0000-000000000001",],
|
"Categories": ["00000000-0000-0000-0000-000000000001",],
|
||||||
"Contributors": get_author(book),
|
# "Contributors": get_author(book),
|
||||||
"CoverImageId": book_uuid,
|
"CoverImageId": book_uuid,
|
||||||
"CrossRevisionId": book_uuid,
|
"CrossRevisionId": book_uuid,
|
||||||
"CurrentDisplayPrice": {"CurrencyCode": "USD", "TotalAmount": 0},
|
"CurrentDisplayPrice": {"CurrencyCode": "USD", "TotalAmount": 0},
|
||||||
|
@ -382,6 +387,7 @@ def get_metadata(book):
|
||||||
"Title": book.title,
|
"Title": book.title,
|
||||||
"WorkId": book_uuid,
|
"WorkId": book_uuid,
|
||||||
}
|
}
|
||||||
|
metadata.update(get_author(book))
|
||||||
|
|
||||||
if get_series(book):
|
if get_series(book):
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
|
@ -400,7 +406,7 @@ def get_metadata(book):
|
||||||
|
|
||||||
|
|
||||||
@kobo.route("/v1/library/tags", methods=["POST", "DELETE"])
|
@kobo.route("/v1/library/tags", methods=["POST", "DELETE"])
|
||||||
@login_required
|
@requires_kobo_auth
|
||||||
# Creates a Shelf with the given items, and returns the shelf's uuid.
|
# Creates a Shelf with the given items, and returns the shelf's uuid.
|
||||||
def HandleTagCreate():
|
def HandleTagCreate():
|
||||||
# catch delete requests, otherwise the are handeld in the book delete handler
|
# catch delete requests, otherwise the are handeld in the book delete handler
|
||||||
|
@ -435,6 +441,7 @@ def HandleTagCreate():
|
||||||
|
|
||||||
|
|
||||||
@kobo.route("/v1/library/tags/<tag_id>", methods=["DELETE", "PUT"])
|
@kobo.route("/v1/library/tags/<tag_id>", methods=["DELETE", "PUT"])
|
||||||
|
@requires_kobo_auth
|
||||||
def HandleTagUpdate(tag_id):
|
def HandleTagUpdate(tag_id):
|
||||||
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.uuid == tag_id,
|
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.uuid == tag_id,
|
||||||
ub.Shelf.user_id == current_user.id).one_or_none()
|
ub.Shelf.user_id == current_user.id).one_or_none()
|
||||||
|
@ -489,7 +496,7 @@ def add_items_to_shelf(items, shelf):
|
||||||
|
|
||||||
|
|
||||||
@kobo.route("/v1/library/tags/<tag_id>/items", methods=["POST"])
|
@kobo.route("/v1/library/tags/<tag_id>/items", methods=["POST"])
|
||||||
@login_required
|
@requires_kobo_auth
|
||||||
def HandleTagAddItem(tag_id):
|
def HandleTagAddItem(tag_id):
|
||||||
items = None
|
items = None
|
||||||
try:
|
try:
|
||||||
|
@ -519,7 +526,7 @@ def HandleTagAddItem(tag_id):
|
||||||
|
|
||||||
|
|
||||||
@kobo.route("/v1/library/tags/<tag_id>/items/delete", methods=["POST"])
|
@kobo.route("/v1/library/tags/<tag_id>/items/delete", methods=["POST"])
|
||||||
@login_required
|
@requires_kobo_auth
|
||||||
def HandleTagRemoveItem(tag_id):
|
def HandleTagRemoveItem(tag_id):
|
||||||
items = None
|
items = None
|
||||||
try:
|
try:
|
||||||
|
@ -628,7 +635,7 @@ def create_kobo_tag(shelf):
|
||||||
|
|
||||||
|
|
||||||
@kobo.route("/v1/library/<book_uuid>/state", methods=["GET", "PUT"])
|
@kobo.route("/v1/library/<book_uuid>/state", methods=["GET", "PUT"])
|
||||||
@login_required
|
@requires_kobo_auth
|
||||||
def HandleStateRequest(book_uuid):
|
def HandleStateRequest(book_uuid):
|
||||||
book = calibre_db.get_book_by_uuid(book_uuid)
|
book = calibre_db.get_book_by_uuid(book_uuid)
|
||||||
if not book or not book.data:
|
if not book or not book.data:
|
||||||
|
@ -802,7 +809,7 @@ def TopLevelEndpoint():
|
||||||
|
|
||||||
|
|
||||||
@kobo.route("/v1/library/<book_uuid>", methods=["DELETE"])
|
@kobo.route("/v1/library/<book_uuid>", methods=["DELETE"])
|
||||||
@login_required
|
@requires_kobo_auth
|
||||||
def HandleBookDeletionRequest(book_uuid):
|
def HandleBookDeletionRequest(book_uuid):
|
||||||
log.info("Kobo book deletion request received for book %s" % book_uuid)
|
log.info("Kobo book deletion request received for book %s" % book_uuid)
|
||||||
book = calibre_db.get_book_by_uuid(book_uuid)
|
book = calibre_db.get_book_by_uuid(book_uuid)
|
||||||
|
|
|
@ -77,6 +77,7 @@ class ReverseProxied(object):
|
||||||
servr = environ.get('HTTP_X_FORWARDED_HOST', '')
|
servr = environ.get('HTTP_X_FORWARDED_HOST', '')
|
||||||
if servr:
|
if servr:
|
||||||
environ['HTTP_HOST'] = servr
|
environ['HTTP_HOST'] = servr
|
||||||
|
self.proxied = True
|
||||||
return self.app(environ, start_response)
|
return self.app(environ, start_response)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -27,7 +27,10 @@ except ImportError:
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from flask import json
|
from flask import json
|
||||||
from .. import logger as log
|
from .. import logger
|
||||||
|
|
||||||
|
|
||||||
|
log = logger.create()
|
||||||
|
|
||||||
|
|
||||||
def b64encode_json(json_data):
|
def b64encode_json(json_data):
|
||||||
|
@ -45,7 +48,8 @@ def to_epoch_timestamp(datetime_object):
|
||||||
def get_datetime_from_json(json_object, field_name):
|
def get_datetime_from_json(json_object, field_name):
|
||||||
try:
|
try:
|
||||||
return datetime.utcfromtimestamp(json_object[field_name])
|
return datetime.utcfromtimestamp(json_object[field_name])
|
||||||
except KeyError:
|
except (KeyError, OSError, OverflowError):
|
||||||
|
# OSError is thrown on Windows if timestamp is <1970 or >2038
|
||||||
return datetime.min
|
return datetime.min
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -159,9 +159,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if c.datatype == 'rating' %}
|
{% if c.datatype == 'rating' %}
|
||||||
<input type="number" min="1" max="5" step="1" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
<input type="number" min="1" max="5" step="0.5" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
||||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
||||||
value="{{ '%d' % (book['custom_column_' ~ c.id][0].value / 2) }}"
|
value="{{ '%.1f' % (book['custom_column_' ~ c.id][0].value / 2) }}"
|
||||||
{% endif %}>
|
{% endif %}>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -174,7 +174,7 @@
|
||||||
{{ c.name }}:
|
{{ c.name }}:
|
||||||
{% for column in entry['custom_column_' ~ c.id] %}
|
{% for column in entry['custom_column_' ~ c.id] %}
|
||||||
{% if c.datatype == 'rating' %}
|
{% if c.datatype == 'rating' %}
|
||||||
{{ '%d' % (column.value / 2) }}
|
{{ '%d' % (column.value / 2) }}{% if ((column.value /2) % 1) != 0 %}{{ '.%d' % (((column.value /2) % 1)*10) }} {% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if c.datatype == 'bool' %}
|
{% if c.datatype == 'bool' %}
|
||||||
{% if column.value == true %}
|
{% if column.value == true %}
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if c.datatype == 'rating' %}
|
{% if c.datatype == 'rating' %}
|
||||||
<input type="number" min="1" max="5" step="1" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}">
|
<input type="number" min="1" max="5" step="0.5" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{% if g.user.role_admin() %}
|
||||||
<h3>{{_('Linked Libraries')}}</h3>
|
<h3>{{_('Linked Libraries')}}</h3>
|
||||||
<table id="libs" class="table">
|
<table id="libs" class="table">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -44,4 +45,5 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1142,7 +1142,7 @@ def advanced_search():
|
||||||
db.cc_classes[c.id].value == custom_query))
|
db.cc_classes[c.id].value == custom_query))
|
||||||
elif c.datatype == 'rating':
|
elif c.datatype == 'rating':
|
||||||
q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any(
|
q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any(
|
||||||
db.cc_classes[c.id].value == int(custom_query) * 2))
|
db.cc_classes[c.id].value == int(float(custom_query) * 2)))
|
||||||
else:
|
else:
|
||||||
q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any(
|
q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any(
|
||||||
func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%")))
|
func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%")))
|
||||||
|
@ -1256,6 +1256,9 @@ def render_archived_books(page, order):
|
||||||
def get_cover(book_id):
|
def get_cover(book_id):
|
||||||
return get_book_cover(book_id)
|
return get_book_cover(book_id)
|
||||||
|
|
||||||
|
@web.route("/robots.txt")
|
||||||
|
def get_robots():
|
||||||
|
return send_from_directory(constants.STATIC_DIR, "robots.txt")
|
||||||
|
|
||||||
@web.route("/show/<int:book_id>/<book_format>", defaults={'anyname': 'None'})
|
@web.route("/show/<int:book_id>/<book_format>", defaults={'anyname': 'None'})
|
||||||
@web.route("/show/<int:book_id>/<book_format>/<anyname>")
|
@web.route("/show/<int:book_id>/<book_format>/<anyname>")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user