diff --git a/goodreads/goodreads.go b/goodreads/goodreads.go index e21b54a..66d96b1 100644 --- a/goodreads/goodreads.go +++ b/goodreads/goodreads.go @@ -173,27 +173,3 @@ func (c *Client) GetBookByTitle(ctx context.Context, bookTitle string, bookAutho return result.Work, nil } - -// SearchBooks search for a book by its title and optionally an author (which can give better results) -// https://www.goodreads.com/api/index#search.books -func (c *Client) SearchBooks(ctx context.Context, bookTitle string, bookAuthor *string) ([]Book, error) { - var bookOverviews []BookOverview - var err error - if bookAuthor == nil || *bookAuthor == "" { - // If author is not set, search for books by title - bookOverviews, err = c.searchBooksByTitle(ctx, bookTitle) - } else { - bookOverviews, err = c.searchBooksByTitleAndAuthor(ctx, bookTitle, *bookAuthor) - } - if err != nil { - return nil, err - } - - // Get book details using their ids - bookDetails, err := c.GetBooksByIds(ctx, BookIds(bookOverviews)) - if err != nil { - return nil, err - } - - return bookDetails, nil -} diff --git a/goodreads/goodreads_test.go b/goodreads/goodreads_test.go index 5f38a39..260e198 100644 --- a/goodreads/goodreads_test.go +++ b/goodreads/goodreads_test.go @@ -10,25 +10,25 @@ import ( ) const ( - TheHobbitBookId = "5907" - TheHobbitBookTitle = "The Hobbit" - TheHobbitBookAuthor = "J.R.R. Tolkien" + GameOfThronesBookId = "13496" + GameOfThronesBookTitle = "A Game of Thrones" + GameOfThronesBookAuthor = "George R.R. Martin" ) func TestGetBookById(t *testing.T) { - book, err := goodreads.DefaultClient.GetBookById(context.Background(), TheHobbitBookId) + book, err := goodreads.DefaultClient.GetBookById(context.Background(), GameOfThronesBookId) require.NoError(t, err) checkTheHobbitBookDetails(t, book) } func TestGetBookByTitle(t *testing.T) { - book, err := goodreads.DefaultClient.GetBookByTitle(context.Background(), TheHobbitBookTitle, nil) + book, err := goodreads.DefaultClient.GetBookByTitle(context.Background(), GameOfThronesBookTitle, nil) require.NoError(t, err) checkTheHobbitBookDetails(t, book) } func TestSearchTitle(t *testing.T) { - books, err := goodreads.DefaultClient.SearchBooks(context.Background(), TheHobbitBookTitle, nil) + books, err := goodreads.DefaultClient.SearchBooks(context.Background(), GameOfThronesBookTitle, nil) require.NoError(t, err) checkTheHobbitBookDetails(t, books[0]) } @@ -36,20 +36,20 @@ func TestSearchTitle(t *testing.T) { func TestSearchTitleAndAuthor(t *testing.T) { books, err := goodreads.DefaultClient.SearchBooks( context.Background(), - TheHobbitBookTitle, - lo.ToPtr(TheHobbitBookAuthor), + GameOfThronesBookTitle, + lo.ToPtr(GameOfThronesBookAuthor), ) require.NoError(t, err) checkTheHobbitBookDetails(t, books[0]) } func checkTheHobbitBookDetails(t *testing.T, book goodreads.Book) { - require.Equal(t, TheHobbitBookTitle, book.Work.Title) - require.Equal(t, TheHobbitBookId, book.BestEdition.Id) - require.Regexp(t, "1546071216l/5907.jpg$", book.BestEdition.ImageURL) + require.Equal(t, GameOfThronesBookTitle, book.Work.Title()) + require.Equal(t, GameOfThronesBookId, book.BestEdition.Id) + require.Regexp(t, "1562726234l/13496.jpg$", book.BestEdition.ImageURL) require.Equal(t, "English", book.BestEdition.Language) - require.Equal(t, TheHobbitBookAuthor, book.Authors[0].Name) - require.Equal(t, "Middle Earth", book.Series[0].Series.Title) - require.Equal(t, "0", *book.Series[0].BookPosition) - require.EqualValues(t, []string{"Fantasy", "Fiction", "Classic"}, book.Genres) + require.Equal(t, GameOfThronesBookAuthor, book.Authors[0].Name) + require.Equal(t, "A Song of Ice and Fire", book.Series[0].Series.Title) + require.Equal(t, "1", *book.Series[0].BookPosition) + require.EqualValues(t, []string{"Fantasy", "Fiction", "High Fantasy"}, book.Genres) } diff --git a/goodreads/search.go b/goodreads/search.go index e28c8e8..66d165c 100644 --- a/goodreads/search.go +++ b/goodreads/search.go @@ -10,26 +10,42 @@ import ( "github.com/samber/lo" ) -func (c *Client) searchBooksByTitle(ctx context.Context, bookTitle string) ([]BookOverview, error) { - return c.searchBooksManyPages(ctx, searchBooksManyPagesInput{ - Query: bookTitle, +// SearchBooks search for a book by its title and optionally an author (which can give better results) +// https://www.goodreads.com/api/index#search.books +func (c *Client) SearchBooks(ctx context.Context, title string, author *string) ([]Book, error) { + if author == nil || *author == "" { + // If author is not set, search for books by title + return c.searchBooksByTitle(ctx, title) + } + + return c.searchBooksByTitleAndAuthor(ctx, title, *author) +} + +func (c *Client) searchBooksByTitle(ctx context.Context, title string) ([]Book, error) { + bookOverviews, err := c.searchBooksManyPages(ctx, searchBooksManyPagesInput{ + Query: title, SearchType: BookSearchTypeTitle, Page: 1, NumPages: 5, }) + if err != nil { + return nil, err + } + + return c.GetBooksByIds(ctx, BookIds(bookOverviews)) } func (c *Client) searchBooksByTitleAndAuthor( ctx context.Context, - bookTitle string, - bookAuthor string, -) ([]BookOverview, error) { + title string, + author string, +) ([]Book, error) { // If searching by title and author, search by author ONLY first to get their books. // We will then search the books for title. // We do NOT search goodreads by title AND author together using the 'all' search type // as goodreads returns awful results, including sometimes none at all. bookOverviews, err := c.searchBooksManyPages(ctx, searchBooksManyPagesInput{ - Query: bookAuthor, + Query: author, SearchType: BookSearchTypeAuthor, Page: 1, NumPages: 15, @@ -38,10 +54,14 @@ func (c *Client) searchBooksByTitleAndAuthor( return nil, err } - // In author books, sort books by similarity to title - sortBookOverviewsByTitleSimilarity(bookOverviews, bookTitle) + books, err := c.GetBooksByIds(ctx, BookIds(bookOverviews)) + if err != nil { + return nil, err + } + + sortBookByTitleSimilarity(books, title) - return bookOverviews, nil + return books, nil } type searchBooksManyPagesInput struct { diff --git a/goodreads/utils.go b/goodreads/utils.go index 710b26a..2bd15d8 100644 --- a/goodreads/utils.go +++ b/goodreads/utils.go @@ -9,20 +9,20 @@ import ( "golang.org/x/exp/slices" ) -func sortBookOverviewsByTitleSimilarity(bookOverviews []BookOverview, title string) { +func sortBookByTitleSimilarity(books []Book, title string) { normalisedDesiredTitle := normaliseBookTitle(title) similarities := make(map[string]float64) - for _, book := range bookOverviews { - similarities[book.Title] = strutil.Similarity( - normaliseBookTitle(book.Title), + for _, book := range books { + similarities[book.Work.FullTitle] = strutil.Similarity( + normaliseBookTitle(book.Work.FullTitle), normalisedDesiredTitle, metrics.NewJaroWinkler(), ) } - slices.SortStableFunc(bookOverviews, func(i, j BookOverview) bool { - return similarities[i.Title] > similarities[j.Title] + slices.SortStableFunc(books, func(i, j Book) bool { + return similarities[i.Work.FullTitle] > similarities[j.Work.FullTitle] }) }