Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- autocomplete_api: generic function to use the autocomplete api from goodreads.com. API is located at "https://www.goodreads.com/book/auto_complete?format=json&q=XXXXXXXXXXX" where q is a keyword. It works particularly well with amazon or isbn identifiers. Example: curl "https://www.goodreads.com/book/auto_complete?format=json&q=B00R3I7OTM" will return a book deskcription with bookId being the goodreads_id equivalent to the asin B00R3I7OTM. - get_goodreads_id_from_autocomplete: specialized method for the goodreads plugin. Tales a list of identidiers, in order of importance (for the end-user) and uses the autocomplete_api to the equivalent goodreads_id. The list of identifiers is in the form of a literal list, stored in the plugin's prefs. For example, ['goodreads', 'amazon_ca', 'amazon', 'isbn']. In this case, the plugins, while trying to search-with-identifiers, will first use a goodreads identifiers if present (no request made in this case). If it's not available, the autocomplete_api is called with the amazon_ca for a match. If not, the amazon identifier is used, and finally the isbn identifier (if any of those identifiers are available). *config.py: - basic changes to allow the users to store their identifier preference. I had to make minor modifications to integrate the new prefs section seemlesly, it entails loading all the defaults and then updating that dictionnary with the actual prefs. *__init__.py: - Made the necessary changes in the indentify method to call autocomplete_api with all cases of "searches by identifier". It simplidfies the process somewhat.
- Loading branch information
Showing
3 changed files
with
110 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from ast import literal_eval | ||
from calibre_plugins.goodreads.config import plugin_prefs, STORE_NAME, KEY_IDENTIFIER_ORDER | ||
from calibre.utils.logging import ThreadSafeLog | ||
|
||
def get_goodreads_id_from_autocomplete(identifiers, timeout, log): | ||
# type: (dict, int, ThreadSafeLog) -> unicode or None | ||
""" | ||
This method allows users to set their own priority for identifier based searches. | ||
The priority is set by changing the order of the key names in the preferences. | ||
:rtype: unicode or None | ||
:param timeout: int: timeout | ||
:param identifiers: dict: available identifiers for this book, will be filtered | ||
and sorted according to plugin_prefs[STORE_NAME][KEY_IDENTIFIER_ORDER] | ||
:param log: ThreadSafeLog: logging utility | ||
:return: unicode or None: a goodread_id or None | ||
""" | ||
if not identifiers: identifiers={} | ||
try: | ||
#key_order is stored as a literal list of keys ['goodreads', 'amazon_ca', 'isbn'] | ||
key_order = literal_eval(plugin_prefs[STORE_NAME][KEY_IDENTIFIER_ORDER]) | ||
#for every key defined in plugin_prefs that exists this book's identifiers, create a | ||
#list(idenfifier_name:identifier_value) where identifier_name is in the same order as | ||
#key_order. | ||
keys = {unicode(identifier_name):unicode(identifiers[identifier_name]) for identifier_name in key_order if identifier_name in identifiers.keys()} | ||
log.info('Identifier keys will be used in this order to find an equivalent goodread_id:', keys) | ||
except: | ||
log.error('The plugin configuration is bad, and you should feel bad.') | ||
return None | ||
|
||
#for every key candidate | ||
for identifier_name,identifier_value in keys.items(): | ||
#goodreads key is not found by using api | ||
if identifier_name == 'goodreads': | ||
return identifier_value | ||
try: | ||
result = autocomplete_api(identifier_value, timeout, log) | ||
goodreads_id = result.get('bookId') | ||
if goodreads_id: | ||
log.info('autocomplete found a match for ', {identifier_name:identifier_value}, ' ==> ', {'goodreads':goodreads_id}) | ||
return goodreads_id | ||
except: | ||
#very likely the only exception here is a timeout | ||
pass | ||
return None | ||
|
||
|
||
def autocomplete_api(search_terms, timeout, log): | ||
# type: (unicode, int, ThreadSafeLog) -> dict or None | ||
""" | ||
:param timeout: int: urlopen will raise an exception | ||
(caught in get_goodreads_id_from_autocomplete) after this time | ||
:param search_terms: unicode: search term(s) | ||
:param log: ThreadSafeLog: logging utility | ||
:return: dict: a dictionnary representing the first book found by the api. | ||
""" | ||
from urllib2 import urlopen | ||
import json | ||
search_terms = search_terms.strip() | ||
if search_terms is None: return None | ||
|
||
autocomplete_api_url = "https://www.goodreads.com/book/auto_complete?format=json&q=" | ||
log.info('autocomplete url:', autocomplete_api_url, search_terms) | ||
response = urlopen(autocomplete_api_url + search_terms, timeout=timeout).read() | ||
if response: | ||
result = json.loads(response) | ||
if len(result) >= 1: | ||
return result[0] | ||
return None |