Books are removed from synced books upon archiving (from kobo or calibre-web side)

unicode texts (title, author) are showing up right on kobo reader
Added some missing kobo routes (prevents 404 response)
Added a lot of debug output on kobo sync requests
This commit is contained in:
Ozzie Isaacs 2021-12-01 20:29:05 +01:00
parent 87e526642c
commit 7640ac1b3b
2 changed files with 27 additions and 13 deletions

View File

@ -22,6 +22,7 @@ import datetime
import os import os
import uuid import uuid
from time import gmtime, strftime from time import gmtime, strftime
import json
try: try:
from urllib import unquote from urllib import unquote
@ -102,6 +103,8 @@ def make_request_to_kobo_store(sync_token=None):
allow_redirects=False, allow_redirects=False,
timeout=(2, 10) timeout=(2, 10)
) )
log.debug("Content: " + str(store_response.content))
log.debug("StatusCode: " + str(store_response.status_code))
return store_response return store_response
@ -110,7 +113,8 @@ def redirect_or_proxy_request():
if request.method == "GET": if request.method == "GET":
return redirect(get_store_url_for_current_request(), 307) return redirect(get_store_url_for_current_request(), 307)
else: else:
# The Kobo device turns other request types into GET requests on redirects, so we instead proxy to the Kobo store ourselves. # The Kobo device turns other request types into GET requests on redirects,
# so we instead proxy to the Kobo store ourselves.
store_response = make_request_to_kobo_store() store_response = make_request_to_kobo_store()
response_headers = store_response.headers response_headers = store_response.headers
@ -205,8 +209,8 @@ def HandleSyncRequest():
books = calibre_db.session.execute(changed_entries.limit(SYNC_ITEM_LIMIT)) books = calibre_db.session.execute(changed_entries.limit(SYNC_ITEM_LIMIT))
else: else:
books = changed_entries.limit(SYNC_ITEM_LIMIT) books = changed_entries.limit(SYNC_ITEM_LIMIT)
log.debug("Books to Sync: {}".format(books.count()))
for book in books: for book in books:
kobo_sync_status.add_synced_books(book.Books.id)
formats = [data.format for data in book.Books.data] formats = [data.format for data in book.Books.data]
if not 'KEPUB' in formats and config.config_kepubifypath and 'EPUB' in formats: if not 'KEPUB' in formats and config.config_kepubifypath and 'EPUB' in formats:
helper.convert_book_format(book.Books.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name) helper.convert_book_format(book.Books.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name)
@ -245,6 +249,7 @@ def HandleSyncRequest():
pass pass
new_books_last_created = max(ts_created, new_books_last_created) new_books_last_created = max(ts_created, new_books_last_created)
kobo_sync_status.add_synced_books(book.Books.id)
if sqlalchemy_version2: if sqlalchemy_version2:
max_change = calibre_db.session.execute(changed_entries max_change = calibre_db.session.execute(changed_entries
@ -330,9 +335,10 @@ def generate_sync_response(sync_token, sync_results, set_cont=False):
extra_headers["x-kobo-sync"] = "continue" extra_headers["x-kobo-sync"] = "continue"
sync_token.to_headers(extra_headers) sync_token.to_headers(extra_headers)
# log.debug("Kobo Sync Content: {}".format(sync_results)) log.debug("Kobo Sync Content: {}".format(sync_results))
response = make_response(jsonify(sync_results), extra_headers) # jsonify decodes the unicode string different to what kobo expects
response = make_response(json.dumps(sync_results), extra_headers)
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response return response
@ -377,7 +383,7 @@ def get_download_url_for_book(book, book_format):
def create_book_entitlement(book, archived): def create_book_entitlement(book, archived):
book_uuid = book.uuid book_uuid = str(book.uuid)
return { return {
"Accessibility": "Full", "Accessibility": "Full",
"ActivePeriod": {"From": convert_to_kobo_timestamp_string(datetime.datetime.now())}, "ActivePeriod": {"From": convert_to_kobo_timestamp_string(datetime.datetime.now())},
@ -404,7 +410,6 @@ def get_description(book):
return book.comments[0].text return book.comments[0].text
# TODO handle multiple authors
def get_author(book): def get_author(book):
if not book.authors: if not book.authors:
return {"Contributors": None} return {"Contributors": None}
@ -412,10 +417,11 @@ def get_author(book):
author_list = [] author_list = []
autor_roles = [] autor_roles = []
for author in book.authors: for author in book.authors:
autor_roles.append({"Name":author.name, "Role":"Author"}) autor_roles.append({"Name":author.name}) #.encode('unicode-escape').decode('latin-1')
author_list.append(author.name) author_list.append(author.name)
return {"ContributorRoles": autor_roles, "Contributors":author_list} return {"ContributorRoles": autor_roles, "Contributors":author_list}
return {"ContributorRoles": [{"Name":book.authors[0].name, "Role":"Author"}], "Contributors": book.authors[0].name} return {"ContributorRoles": [{"Name":book.authors[0].name}],
"Contributors": book.authors[0].name}
def get_publisher(book): def get_publisher(book):
@ -472,9 +478,7 @@ def get_metadata(book):
"IsSocialEnabled": True, "IsSocialEnabled": True,
"Language": "en", "Language": "en",
"PhoneticPronunciations": {}, "PhoneticPronunciations": {},
# TODO: Fix book.pubdate to return a datetime object so that we can easily "PublicationDate": convert_to_kobo_timestamp_string(book.pubdate),
# convert it to the format Kobo devices expect.
"PublicationDate": book.pubdate,
"Publisher": {"Imprint": "", "Name": get_publisher(book),}, "Publisher": {"Imprint": "", "Name": get_publisher(book),},
"RevisionId": book_uuid, "RevisionId": book_uuid,
"Title": book.title, "Title": book.title,
@ -489,7 +493,7 @@ def get_metadata(book):
"Number": get_seriesindex(book), # ToDo Check int() ? "Number": get_seriesindex(book), # ToDo Check int() ?
"NumberFloat": float(get_seriesindex(book)), "NumberFloat": float(get_seriesindex(book)),
# Get a deterministic id based on the series name. # Get a deterministic id based on the series name.
"Id": uuid.uuid3(uuid.NAMESPACE_DNS, name), "Id": str(uuid.uuid3(uuid.NAMESPACE_DNS, name)),
} }
return metadata return metadata
@ -958,6 +962,8 @@ def HandleBookDeletionRequest(book_uuid):
ub.session.merge(archived_book) ub.session.merge(archived_book)
ub.session_commit() ub.session_commit()
if archived_book.is_archived:
kobo_sync_status.remove_synced_book(book_id)
return "", 204 return "", 204
@ -986,11 +992,16 @@ def HandleUserRequest(dummy=None):
@kobo.route("/v1/products/<dummy>/recommendations", methods=["GET", "POST"]) @kobo.route("/v1/products/<dummy>/recommendations", methods=["GET", "POST"])
@kobo.route("/v1/products/<dummy>/nextread", methods=["GET", "POST"]) @kobo.route("/v1/products/<dummy>/nextread", methods=["GET", "POST"])
@kobo.route("/v1/products/<dummy>/reviews", methods=["GET", "POST"]) @kobo.route("/v1/products/<dummy>/reviews", methods=["GET", "POST"])
@kobo.route("/v1/products/featured/<dummy>", methods=["GET", "POST"])
@kobo.route("/v1/products/featured/", methods=["GET", "POST"])
@kobo.route("/v1/products/books/external/<dummy>", methods=["GET", "POST"]) @kobo.route("/v1/products/books/external/<dummy>", methods=["GET", "POST"])
@kobo.route("/v1/products/books/series/<dummy>", methods=["GET", "POST"]) @kobo.route("/v1/products/books/series/<dummy>", methods=["GET", "POST"])
@kobo.route("/v1/products/books/<dummy>", methods=["GET", "POST"]) @kobo.route("/v1/products/books/<dummy>", methods=["GET", "POST"])
@kobo.route("/v1/products/books/<dummy>/", methods=["GET", "POST"])
@kobo.route("/v1/products/dailydeal", methods=["GET", "POST"]) @kobo.route("/v1/products/dailydeal", methods=["GET", "POST"])
@kobo.route("/v1/products/deals", methods=["GET", "POST"])
@kobo.route("/v1/products", methods=["GET", "POST"]) @kobo.route("/v1/products", methods=["GET", "POST"])
@kobo.route("/v1/affiliate", methods=["GET", "POST"])
def HandleProductsRequest(dummy=None): def HandleProductsRequest(dummy=None):
log.debug("Unimplemented Products Request received: %s", request.base_url) log.debug("Unimplemented Products Request received: %s", request.base_url)
return redirect_or_proxy_request() return redirect_or_proxy_request()

View File

@ -54,6 +54,7 @@ from .helper import check_valid_domain, render_task_status, check_email, check_u
from .pagination import Pagination from .pagination import Pagination
from .redirect import redirect_back from .redirect import redirect_back
from .usermanagement import login_required_if_no_ano from .usermanagement import login_required_if_no_ano
from .kobo_sync_status import remove_synced_book
from .render_template import render_title_template from .render_template import render_title_template
feature_support = { feature_support = {
@ -206,6 +207,8 @@ def toggle_archived(book_id):
archived_book.is_archived = True archived_book.is_archived = True
ub.session.merge(archived_book) ub.session.merge(archived_book)
ub.session_commit("Book {} archivebit toggled".format(book_id)) ub.session_commit("Book {} archivebit toggled".format(book_id))
if archived_book.is_archived:
remove_synced_book(book_id)
return "" return ""