-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathgoodreads.py
More file actions
executable file
·145 lines (117 loc) · 4.78 KB
/
goodreads.py
File metadata and controls
executable file
·145 lines (117 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# -*- coding: utf-8 -*-
from textwrap import dedent
import goodreads_api_client as gr
import pycountry
from .config import config
from .logging import log
from .calibre import read_metadata
from collections import OrderedDict
config.register(
'Goodreads', 'api_key',
dedent("""\
To find your Goodreads API key, login to https://www.goodreads.com/api/keys
Enter the API Key below
API Key"""))
EXCLUDED_WORDS = ['read', 'favorites', 'book',
'own', 'series', 'novel', 'kindle', 'shelf'
'library', 'buy', 'abandoned',
'audible', 'audio', 'finish', 'wish']
def _extract_authors(authors):
if isinstance(authors['author'], OrderedDict):
return [{
'name': authors['author']['name'],
'link': authors['author']['link']
}]
else:
return [_extract_author(auth)
for auth in authors['author']]
def _extract_author(auth):
return {
'name': auth['name'],
'link': auth['link']
}
def _extract_language(alpha_3):
try:
return pycountry.languages.get(alpha_3=alpha_3).name
except AttributeError:
try:
return pycountry.languages.get(alpha_2=alpha_3[:2]).name
except AttributeError:
# I give up
return input('Please specify the book\'s Language: ')
def _extract_shelves(shelves, take):
# source for tags e.g. sci-fi
return [_extract_shelf(shelf)
for shelf in filter(_exclude_well_known,
sorted(shelves, key=_shelf_sort_key,
reverse=True)[:take])]
def _exclude_well_known(s):
return not any(w in s['@name'] for w in EXCLUDED_WORDS)
def _shelf_sort_key(s):
return int(s['@count'])
def _extract_shelf(shelf):
return {'name': shelf['@name'], 'count': shelf['@count']}
def _process_book(books):
keys_wanted = ['id', 'title', 'isbn', 'isbn13', 'description',
'language_code', 'publication_year', 'publisher',
'image_url', 'url', 'authors', 'average_rating',
'work', 'popular_shelves']
book = {k: v for k, v in books if k in keys_wanted}
book['authors'] = _extract_authors(book['authors'])
book['ratings_count'] = int(book['work']['ratings_count']['#text'])
book['language'] = _extract_language(book['language_code'])
book['shelves'] = _extract_shelves(book['popular_shelves']['shelf'], 10)
return book
class Goodreads(object):
def __init__(self, interactive=True):
self.goodreads = gr.Client(
developer_key=config.get('Goodreads', 'api_key'))
def show_by_isbn(self, isbn):
return _process_book(self.goodreads.Book.show_by_isbn(
isbn).items())
def search(self, path):
book = read_metadata(path)
isbn = ''
try:
isbn = book['Identifiers'].split(':')[1].split(',')[0]
except KeyError:
pass
if isbn:
log.debug("Searching Goodreads by ISBN {} for '{}'",
isbn, book['Title'])
return self.show_by_isbn(isbn)
elif book['Title']:
search_term = book['Title']
log.debug(
"Searching Goodreads by Title only for '{}'", search_term)
book_results = self.goodreads.search_book(search_term)
print("Results:")
for i, book in enumerate(book_results['results']['work']):
print('{}: {} by {} ({})'
.format(i, book['best_book']['title'],
book['best_book']['author']['name'],
book['original_publication_year']
.get('#text', '')))
while True:
choice = input('Select number or enter an alternate'
' search term'
' (or an ISBN with isbn: prefix):'
' [0-{}, 0 default] '
.format(
len(book_results['results']['work']) - 1))
try:
choice = int(choice)
except ValueError:
if choice:
return self.show_by_isbn(choice.replace('isbn:', ''))
choice = 0
try:
result = book_results['results']['work'][choice]
except IndexError:
pass
else:
id = result['best_book']['id'].get('#text', '')
log.debug("Selected Goodreads item {}", id)
log.debug("Searching Goodreads by ID {}", id)
return _process_book(self.goodreads.Book.show(
id).items())