anpigon / obsidian-book-search-plugin

Obsidian plugin that automatically creates notes by searching for books
MIT License
464 stars 51 forks source link

[Feature Request] Replace the thumbnail of the cover with a HQ version of the cover #48

Open ltctceplrm opened 2 years ago

ltctceplrm commented 2 years ago

It seems like if you use this URL https://books.google.com/books/publisher/content/images/frontcover/\(bookImgId)?fife=w400-h600&source=gbs_api and replace (bookImgId) with the book ID then you can have a HQ version of the cover instead of the current thumbnail.

I embed the cover inside the note itself so the current thumbnail just doesn't look very pretty, if could it use the HQ cover instead then it would be great

timrosenberg commented 2 years ago

Have you found a way to do this other than doing it manually?

ltctceplrm commented 2 years ago

Well I found a semi automatic way to do it, I made a templater search and replace script and configured a hotkey so it loads the template and replaces the LQ url with the HQ one. It would be better if it would work when the note gets created but I wasn't able to do that, this way works pretty well for me though so it's good enough for now. I still hope anpigon will add it natively in the plugin.

Here's the template:

<%* 
var file = app.workspace.getActiveFile()
var t = await app.vault.read(file)
var s = t.replaceAll("http://books.google.com/books/content?id=", "https://books.google.com/books/publisher/content/images/frontcover/").replaceAll("&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api","?fife=w600-h900&source=gbs_api").replaceAll("&printsec=frontcover&img=1&zoom=1","?fife=w600-h900&source=gbs_api")

app.vault.modify(file, s)
-%>

Edit: Sometimes there are several versions of books to choose from and some of those only have LQ images so you sometimes need to select another version and try again.

timrosenberg commented 2 years ago

Thank you! I'm such a noob it took me over an hour to figure out how to use this; but, I did it and it works flawlessly.

For future readers:

  1. Copy that script from above.
  2. Paste it into a new Obsidian note.
  3. Give the note a memorable title (mine is HQ Book Cover).
  4. Move that note into the folder with your Templater templates.
  5. Open one of your book notes made with the Book Search Plugin. Or, use the Book Search Plugin to make a book note.
  6. Hit Command-P to open the command palate.
  7. Type "tem" then select "Templater: Open Insert Template modal".
  8. Select your new script note (again, mine is HQ Book Cover) and hit return.
  9. Voila! Your low-quality images are replaced with high-quality ones.

If you are going to do this a lot, it will be faster to assign a hotkey to invoke this Templater script. Here's how you do it:

  1. Go to Templater settings and find the "Template Hotkeys" section.
  2. Click "Add new hotkey for template".
  3. In the box, search for your new HQ Book Cover script. Select it.
  4. Hit the "Plus" button, which takes you to the core Hotkeys Plugin.
  5. Hit the "Plus" button next to your new script note. This allows you to set the hotkeys.
  6. Pick your hotkeys. Mine is command-shift-h.

Now, all you need to do is open or create a book note, smash the hotkeys, and you're done!

uroybd commented 1 year ago

Well I found a semi automatic way to do it, I made a templater search and replace script and configured a hotkey so it loads the template and replaces the LQ url with the HQ one. It would be better if it would work when the note gets created but I wasn't able to do that, this way works pretty well for me though so it's good enough for now. I still hope anpigon will add it natively in the plugin.

Here's the template:

<%* 
var file = app.workspace.getActiveFile()
var t = await app.vault.read(file)
var s = t.replaceAll("http://books.google.com/books/content?id=", "https://books.google.com/books/publisher/content/images/frontcover/").replaceAll("&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api","?fife=w600-h900&source=gbs_api").replaceAll("&printsec=frontcover&img=1&zoom=1","?fife=w600-h900&source=gbs_api")

app.vault.modify(file, s)
-%>

Edit: Sometimes there are several versions of books to choose from and some of those only have LQ images so you sometimes need to select another version and try again.

A non-templater solution for this to get the cover in one go:

<%=book.coverUrl ? `https://books.google.com/books/publisher/content/images/frontcover/${[...book.coverUrl.split("&")[0].matchAll(/id.?(.*)/g)][0][1]}?fife=w600-h900&source=gbs_api` : ''%>

This will build the same URL on the note creation via this plugin.

ltctceplrm commented 1 year ago

Impressive @uroybd, I didn't even know that was possible, thanks for the heads up.

ctwhome commented 7 months ago

Calling the Google API with the zoom parameter - 0 removes the scaling

https://books.google.com/books/content?id=6xVTDwAAQBAJ&printsec=frontcover&img=1&zoom=0

The default set right now in the plugin is 5, which makes the image so small... Although the @uroybd is nice, it won't download the image locally, meaning that it needs internet / the Google API might change in the future breaking all cover images

kitschpatrol commented 2 months ago

I just ran into this as well. Bit of a rabbit hole.

I have a fork here which implements additional logic to use the largest image available . I found it wasn't as simple as manipulating the zoom URL parameter since there's no guarantee that the zoom=0 variation will exist for all search results. Deleting the zoom parameter entirely also seemed promising, but again didn't work in 100% of cases across a ~400 book test collection.

It turns out the results of a query request provides only partial information for each volume, and only ever returns smallThumbnail and thumbnail fields in the imageLinks object, even when more variations are available.

For example:

curl "https://www.googleapis.com/books/v1/volumes?q=isbn:9780143122791" | jq '.items[0].volumeInfo.imageLinks'

Returns:

{
  "smallThumbnail": "http://books.google.com/books/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
  "thumbnail": "http://books.google.com/books/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
}

However, a query directly to the /volumes/$ID endpoint with a specific Google Books ID value will give you additional cover image size fields:

 curl "https://www.googleapis.com/books/v1/volumes/OkECDAAAQBAJ" | jq '.volumeInfo.imageLinks'

Returns:

 {
  "smallThumbnail": "http://books.google.com/books/publisher/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE70Al9vLkyfAWM8NGEY07WJfZxg9wB9LRIhqbmNX00WcNV6xE6QLWs4jPgBRgVZEU9xY_md0YH2xIbTFWotbMGd7JTDRKmyaeuryDHW98b1nNOoZX1JGIj7HEfxfCauR6xRjcsjd&source=gbs_api",
  "thumbnail": "http://books.google.com/books/publisher/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE729IuSIj1hsOnWIu-e4uY8iM5bgW87dLtlNMjC3QJCH0W6IzxZPkfjCbBUltbhe418bOYPnsTtJ1vfX9DZeOaYgh-QXbCITwV0ZZ1i_n5u-mVRm6Sc2bHA5fNRNXo7MiOGYZwvL&source=gbs_api",
  "small": "http://books.google.com/books/publisher/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE73u2pOC1AlXAHTmyJ4-tBBtcTP5g-Cr4X98LGYC9dpgZbJz2yf7ugK0181VxuWsDSjXfVZBfQXhoRcjIX4TcXWIG_t_7ZP1XOTFhFRtoo4ExbAtFqpLBw1ugtQbcYcB4pelWPAk&source=gbs_api",
  "medium": "http://books.google.com/books/publisher/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE71Ra8v9Tu5hEPiLgWNYW11CWPEE0t7rNr1uFUKUUdvbre4WFLAAr5upEIWPVmc_D0CIYoPNMDFuuUWxKJvehFjn97kvBlVWY51l5QRqfxeciXeHvpgMx2ZfsfsMAU1uD9UZTzfT&source=gbs_api",
  "large": "http://books.google.com/books/publisher/content?id=OkECDAAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE70kPNxq6FamleVQ9eiBBqtXJInyiPTjcqMujerxJFJ--FvIbmPD25r2TEAsrsyppvldaASXDlyMYFThGKVhtOvGGFM4809KBLJeTr2uB9X2Tku8WVjw2Cek2sbARECO6DJZg7hJ&source=gbs_api"
}

So, the fork makes an additional query to get this extra info and then picks the URL from the largest available image size key.

I'd submit this as a PR, but a proper fix would require some additional work I don't have time for at the moment. The issue with the fork is that the plugin's current architecture doesn't preserve the Google book ID value as part of the book query results, since it's designed to pass the search results straight through without additional queries — so instead I'm making an extra query for every search result, which is both slow and burns through the API quota. Since there's no equivalent code path for the Naven API implementation, any "quick fix" for this that I could think of would leak Google-specific implementation details into the generalized abstraction for querying and receiving book search results, which would not be great.

And even then, the larger cover images are often of mediocre quality. I sometimes (though not in this example case) found better quality cover images from openlibrary.org, e.g. https://covers.openlibrary.org/b/isbn/9780143122791-L.jpg.

Given the inconsistency in image quality across sources, maybe a better long-term architecture would separate the cover search logic from the book metadata search logic, and then present candidate covers from a number of services for the user to select, or use some kind of heuristic on the available cover images to automatically identify the best candidate (fraught).

shawnmclean commented 2 months ago

or use some kind of heuristic on the available cover images to automatically identify the best candidate (fraught).

@kitschpatrol have you thought of any heuristics?

I'm running into this same issue with inconsistent images across google and openlibrary.

In my case, I'm running background jobs so I don't mind downloading images and ranking them by quality.

I also found that maybe 40% of about 500 books I've tested on are not on OpenLibrary.

kitschpatrol commented 2 months ago

Picking the "best" cover image is kind of an unbounded problem... and it really means two things in the context of this project:

  1. Identifying the image that's actually a cover and not the scan of the first page or something else.
  2. Identifying the highest quality cover from a number of of choices (which is not always necessarily a trivial question of file size or pixel dimensions).

It's easy to think of a couple heuristics, but harder to have confidence in them:

Any combination of these techniques could be fun to experiment with and might work (sometimes), but personally the collection I'm cataloging isn't big enough to warrant further adventures in automation.