@ -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 ( )