Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# abs-tract

This is an "all-in-one" book metadata provider for AudiobookShelf that can currently pull metadata from Goodreads and Kindle Store.
This is an "all-in-one" book metadata provider for AudiobookShelf that can currently pull metadata from Goodreads, Kindle Store and BookBeat.

Current metadata providers plan to be improved, and other metadata providers are on the roadmap.

Expand Down Expand Up @@ -55,6 +55,35 @@ I'm glad you asked - It's a fun play on words. AudiobookShelf is often abbreviat
- Publish Year - of edition chosen by Amazon. **Not original publish year**
- ASIN

### BookBeat

#### Pros:
- High-quality covers (2048x2048)
- Comprehensive metadata including narrators and duration
- Supports multiple markets and languages
- Format filtering (audiobook/ebook)

#### Cons:
- Content availability varies by market (country)
- Some books may not be available in certain formats in all markets

#### Metadata Provided:
- Title
- Subtitle
- Author(s)
- Narrator(s)
- Cover (2048x2048 might take a few seconds to appear)
- Description
- Duration (in minutes)
- ISBN
- Genres
- Language
- Series Name
- Series Position
- Publisher
- Published Year
- Tags

## Running

The best way to run abs-tract is to use Docker. To run abs-tract using Docker, use the following command:
Expand Down Expand Up @@ -87,6 +116,14 @@ curl --request GET \
--url "http://$ADDRESS:5555/kindle/uk/search?query=The+Hobbit&author=J.R.R.+Tolkien"
```

### BookBeat

```bash
ADDRESS=localhost
curl --request GET \
--url "http://$ADDRESS:5555/bookbeat/uk/audiobook/en/search?query=The+Hobbit&author=J.R.R.+Tolkien"
```

## Setup with AudiobookShelf

You can then set up abs-tract in AudiobookShelf.
Expand Down Expand Up @@ -124,6 +161,76 @@ Region can be one of the following:
- uk - United Kingdom
- us - United States

### BookBeat

- Name: **BookBeat**
- URL: `http://<your_address>:5555/bookbeat/<market>/<format>/<language>`
- e.g. `192.168.1.100:5555/bookbeat/uk/all/en,de`
- Authorization Header Value: **Leave this unset**

Market determines which BookBeat regional catalog to search. Different markets may have different book availability. Market can be one of the following:

- at - Austria
- be - Belgium
- bg - Bulgaria
- hr - Croatia
- cy - Cyprus
- cz - Czech Republic
- dk - Denmark
- ee - Estonia
- fi - Finland
- fr - France
- de - Germany
- gr - Greece
- hu - Hungary
- ie - Ireland
- it - Italy
- lv - Latvia
- lt - Lithuania
- lu - Luxembourg
- mt - Malta
- nl - Netherlands
- no - Norway
- pl - Poland
- pt - Portugal
- ro - Romania
- sk - Slovakia
- si - Slovenia
- es - Spain
- se - Sweden
- ch - Switzerland
- uk - United Kingdom

Format filters results by book type. Note that not all books are available in all formats in every market. Format can be one of the following:

- all - Search both audiobooks and ebooks
- audiobook - Search audiobooks only
- ebook - Search ebooks only

Language can be "all" or comma separated list of:

- en - English
- de - German
- ar - Arabic
- eu - Basque
- ca - Catalan
- cs - Czech
- da - Danish
- nl - Dutch
- et - Estonian
- fi - Finnish
- fr - French
- hu - Hungarian
- it - Italian
- nb - Norwegian
- nn - Norwegian Nynorsk
- pl - Polish
- pt - Portuguese
- ru - Russian
- es - Spanish
- sv - Swedish
- tr - Turkish

## FAQ

### Why is Goodreads not returning covers?
Expand Down
26 changes: 26 additions & 0 deletions bookbeat/book.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package bookbeat

type BookSeries struct {
Series string `json:"series"`
Sequence int `json:"sequence,omitempty"`
}

type Book struct {
ID int `json:"id"`
Type string `json:"type"`
Title string `json:"title"`
Subtitle string `json:"subtitle,omitempty"`
Authors string `json:"authors"`
Narrators string `json:"narrators,omitempty"`
Publisher string `json:"publisher,omitempty"`
PublishedYear int `json:"publishedYear,omitempty"`
Description string `json:"description,omitempty"`
ISBN string `json:"isbn,omitempty"`
ASIN string `json:"asin,omitempty"`
Language string `json:"language,omitempty"`
Duration int `json:"duration,omitempty"`
Genres []string `json:"genres,omitempty"`
Tags []string `json:"tags,omitempty"`
Series *BookSeries `json:"series,omitempty"`
Cover string `json:"cover,omitempty"`
}
105 changes: 105 additions & 0 deletions bookbeat/book_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package bookbeat

import (
"time"
)

type RatingDistribution struct {
Num1 int `json:"1"`
Num2 int `json:"2"`
Num3 int `json:"3"`
Num4 int `json:"4"`
Num5 int `json:"5"`
}

type Rating struct {
RatingValue float64 `json:"ratingValue"`
NumberOfRatings int `json:"numberOfRatings"`
RatingDistribution RatingDistribution `json:"ratingDistribution"`
}

type Badge struct {
ID string `json:"id"`
TranslationKey string `json:"translationKey"`
Type string `json:"type"`
Icon string `json:"icon"`
}

type Genre struct {
Genreid int `json:"genreid"`
Name string `json:"name"`
}

type Series struct {
Count int `json:"count"`
Partindex int `json:"partindex"`
Prevbookid int `json:"prevbookid"`
Nextbookid int `json:"nextbookid"`
ID int `json:"id"`
Name string `json:"name"`
Partnumber int `json:"partnumber"`
URL string `json:"url"`
}

type CopyrightOwner struct {
Year int `json:"year"`
Name string `json:"name"`
}

type Contributor struct {
ID int `json:"id"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Displayname string `json:"displayname"`
Role string `json:"role"`
Description string `json:"description"`
Booksurl string `json:"booksurl"`
}

type Edition struct {
ID int `json:"id"`
Isbn string `json:"isbn"`
Format string `json:"format"`
Language string `json:"language"`
Published time.Time `json:"published"`
BookBeatPublishDate time.Time `json:"bookBeatPublishDate"`
BookBeatUnpublishDate time.Time `json:"bookBeatUnpublishDate"`
Availablefrom time.Time `json:"availablefrom"`
Publisher string `json:"publisher"`
CopyrightOwners []CopyrightOwner `json:"copyrightOwners"`
Contributors []Contributor `json:"contributors"`
Previewenabled bool `json:"previewenabled"`
}

type BookResponse struct {
ID int `json:"id"`
Title string `json:"title"`
Subtitle string `json:"subtitle"`
Originaltitle string `json:"originaltitle"`
Author string `json:"author"`
Shareurl string `json:"shareurl"`
Summary string `json:"summary"`
Grade float64 `json:"grade"`
Rating Rating `json:"rating"`
NarratingRating Rating `json:"narratingRating"`
Cover string `json:"cover"`
Narrator string `json:"narrator"`
Translator string `json:"translator"`
Language string `json:"language"`
Published time.Time `json:"published"`
Originalpublishyear int `json:"originalpublishyear"`
Ebooklength float64 `json:"ebooklength"`
Ebookduration float64 `json:"ebookduration"`
Audiobooklength int `json:"audiobooklength"` // in seconds
Genres []Genre `json:"genres"`
Editions []Edition `json:"editions"`
Upcomingeditions []Edition `json:"upcomingeditions"`
Markets []string `json:"markets"`
Series *Series `json:"series"`
Contenttypetags []string `json:"contenttypetags"`
Relatedreadingsurl string `json:"relatedreadingsurl"`
Nextcontenturl string `json:"nextcontenturl"`
Type int `json:"Type"`
Bookappviewurl string `json:"bookappviewurl"`
Badges []Badge `json:"badges"`
}
Loading
Loading