Skip to content

Commit a3a3773

Browse files
committed
Initial commit
0 parents  commit a3a3773

File tree

3 files changed

+391
-0
lines changed

3 files changed

+391
-0
lines changed

.github/FUNDING.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# These are supported funding model platforms
2+
3+
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4+
patreon: # Replace with a single Patreon username
5+
open_collective: # Replace with a single Open Collective username
6+
ko_fi: # Replace with a single Ko-fi username
7+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9+
liberapay: # Replace with a single Liberapay username
10+
issuehunt: # Replace with a single IssueHunt username
11+
otechie: # Replace with a single Otechie username
12+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13+
custom: https://www.buymeacoffee.com/elawsdev4

README.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Books script for Obsidian's Quickadd plugin
2+
3+
## Demo
4+
![googleBooksDemo](https://user-images.githubusercontent.com/52013479/151622323-294cca54-f661-4ff3-95e6-4fe7a7e7ea9b.gif)
5+
6+
If this script helped you and you wish to contribute :)
7+
8+
<a href="https://www.buymeacoffee.com/elawsdev4" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
9+
10+
## Description
11+
12+
This script allows you to easily insert a book note into your Obsidian vault using [Quickadd plugin](https://github.com/chhoumann/quickadd) by @chhoumann. **Now also works on Mobile (make sure you use latest QuickAdd) !**
13+
Possible to query book using :
14+
- a book title or ISBN (10 or 13).
15+
- (optional) author name
16+
17+
It's also possible to query book using author name only (just skip book title prompt).
18+
19+
The `(i)` prefix in search suggestions indicates that an image is available for this book.
20+
21+
We use Google Books API to get the book information.
22+
23+
An API KEY for Google Books is needed to use this script : it can be obtained [here](https://console.developers.google.com/apis/credentials). Steps to obtain this key are detailed below (see [How to obtain Google Book's API key](#how-to-obtain-google-books-api-key)).
24+
25+
## Disclaimer
26+
27+
The script and this tutorial are based on [Macro_MovieAndSeriesScript.md](https://github.com/chhoumann/quickadd/blob/master/docs/Examples/Macro_MovieAndSeriesScript.md) by @chhoumann.
28+
29+
**Please never run a script that you don't understand. I cannot and will not be liable for any damage caused by the use of this script. Regularly make a backup of your Obsidian's vault !**
30+
31+
## How to obtain Google Book's API key
32+
33+
1. Visit [this website](https://console.developers.google.com/apis/credentials).
34+
2. Login using your Google account.
35+
3. When prompted, accept the terms of use :
36+
37+
![0](https://user-images.githubusercontent.com/52013479/151619294-85229684-821d-4d50-b99d-c4b9aba70b8f.png)
38+
39+
4. Click on "Create a project" :
40+
41+
![1](https://user-images.githubusercontent.com/52013479/151619359-38879068-595b-4c10-a3e6-ffc575755f1f.png)
42+
43+
5. Enter a project name :
44+
45+
![2](https://user-images.githubusercontent.com/52013479/151619395-8835e1b5-218d-4763-89a4-7ff89ed13fcb.png)
46+
47+
6. Back on the credentials page, click on "Create credentials" :
48+
49+
![3](https://user-images.githubusercontent.com/52013479/151619475-89154b57-bf7f-435b-ba54-e46d24547c74.png)
50+
51+
7. In the menu that appeared, select "API Key" :
52+
53+
![4](https://user-images.githubusercontent.com/52013479/151619531-7555f6cf-16b7-4af8-8c79-4c252b614af8.png)
54+
55+
8. You should see your API key. Close the window :
56+
57+
![5](https://user-images.githubusercontent.com/52013479/151619579-e4691a4b-89ca-4420-ac4e-9dcd465bae40.png)
58+
59+
9. Here is your API key :
60+
61+
![key](https://user-images.githubusercontent.com/52013479/151620113-763477bf-1d4d-4888-af60-932d4c6635d2.png)
62+
63+
10. We must now enable Google Books API for this key. Back on the credentials page, click on "APIs and services" :
64+
65+
![6](https://user-images.githubusercontent.com/52013479/151619643-762730ff-ee6c-4053-8882-f4c175d0310b.png)
66+
67+
11. Click on "Enable APIs and services" :
68+
69+
![7](https://user-images.githubusercontent.com/52013479/151619722-1e7c04e3-be23-4d31-bde1-b97d88b6590a.png)
70+
71+
12. Enter "Google books" in the search bar that appeared :
72+
73+
![8](https://user-images.githubusercontent.com/52013479/151619784-626bb529-190f-49a0-9ad8-095a702f3f99.png)
74+
75+
13. Select "Books API" :
76+
77+
![9](https://user-images.githubusercontent.com/52013479/151619814-ae050972-ae34-4eec-8257-f982d6b7485c.png)
78+
79+
14. Enable Google Books API by clicking on "Enable" :
80+
81+
![10](https://user-images.githubusercontent.com/52013479/151619886-f5774148-6489-45c7-be64-47211e45f704.png)
82+
83+
84+
## Installation
85+
![googleBooksInstall](https://user-images.githubusercontent.com/52013479/151622434-7ce2ebbc-847f-48cb-b867-d103238ec5bf.gif)
86+
87+
0. Make sure you use latest Quickadd version (at least 0.5.1) !
88+
1. Save the [script](https://github.com/Elaws/script_googleBooks_quickAdd/releases) to your vault somewhere. Make sure it is saved as a JavaScript file, meaning that it has the `.js` at the end.
89+
2. Create a new template in your designated templates folder. Example template is provided below.
90+
3. Open the Macro Manager by opening the QuickAdd plugin settings and clicking `Manage Macros`.
91+
4. Create a new Macro - you decide what to name it.
92+
5. Add the user script to the command list.
93+
6. Add a new Template step to the macro. This will be what creates the note in your vault. Settings are as follows:
94+
1. Set the template path to the template you created.
95+
2. Enable File Name Format and use `{{VALUE:fileName}}` as the file name format. You can specify this however you like. The `fileName` value is the name of book without illegal file name characters.
96+
3. The remaining settings are for you to specify depending on your needs.
97+
7. Click on the cog icon to the right of the script step to configure the script settings. This should allow you to enter the API key you got from Google Books API. **Make sure no spaces are inserted before or after the key !**
98+
8. Go back out to your QuickAdd main menu and add a new Macro choice. Again, you decide the name. This is what activates the macro.
99+
9. Attach the Macro to the Macro Choice you just created. Do so by clicking the cog ⚙ icon and selecting it.
100+
101+
You can now use the macro to create notes with book information in your vault !
102+
103+
### Example template
104+
105+
Please also find a definition of the variables used in this template below (see : [Template variable definitions](#template-variable-definitions)).
106+
107+
```markdown
108+
# {{VALUE:title}}
109+
110+
Title:: {{VALUE:title}}
111+
linking:: [[% Novels]]
112+
Tags:: #📥/📚/{{VALUE:tag}}
113+
Author:: {{VALUE:authors}}
114+
Publish date:: {{VALUE:release}}
115+
Cover:: {{VALUE:thumbnail}}
116+
ISBN10:: {{VALUE:isbn10}}
117+
ISBN13:: {{VALUE:isbn13}}
118+
URL:: [Goodreads]({{VALUE:goodreadsURL}})
119+
Rating:: {{VALUE:rating}}
120+
Read:: {{VALUE:read}}
121+
Recommender:: {{VALUE:recommender}}
122+
Date:: {{DATE}}
123+
Comment:: {{VALUE:comment}}
124+
125+
```
126+
127+
## Dataview rendering
128+
129+
Here is the dataview query used in the demo (replace `PATH` by your videogames notes path) :
130+
131+
```dataview
132+
TABLE WITHOUT ID
133+
134+
("[[" + file.name + "|" + Title + "]]") AS Title,
135+
Author,
136+
publish-date AS "Publish date",
137+
("![coverImg|100](" + Cover + ")") as Cover,
138+
rating AS "Rating",
139+
Recommender,
140+
Comment,
141+
Date,
142+
URL
143+
144+
FROM "PATH"
145+
146+
SORT Title
147+
```
148+
149+
The banner at the top of the document is rendered using [Obsidian-banners](https://github.com/noatpad/obsidian-banners) plugin.
150+
151+
## Template variable definitions
152+
153+
Please find here a definition of the possible variables to be used in your template. Simply write `{{VALUE:name}}` in your template, and replace `name` by the desired book data, including :
154+
155+
`fileName` : Title of the book without illegal characters. Possibly used in template configuration to name your file.
156+
157+
`title` : The title of the book.
158+
159+
`tag` : A colored square that is red if unread, orange if read.
160+
161+
`authors` : Book's author.
162+
163+
`release` : The year this edition of the book was published.
164+
165+
`thumbnail` : A book cover, whenever possible.
166+
167+
`isbn10` : The ISBN 10 of the book.
168+
169+
`isbn13` : The ISBN 13 of the book.
170+
171+
`goodreadsURL` : An URL that uses the ISBN to request Goodreads book page. This may fail if ISBN returned by Google is not in the database of Goodreads.
172+
173+
`rating` : Your book rating, /10.
174+
175+
`read` : If you read the book, this equals 1, otherwise 0 (this helps to filter dataview query).
176+
177+
`recommender` : The person (or organization, etc...) that recommended the book to you.
178+
179+
`comment` : A short personal comment on the book.

script_googleBooks_quickAdd.js

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
const notice = (msg) => new Notice(msg, 5000);
2+
const log = (msg) => console.log(msg);
3+
4+
5+
// Do NOT edit this.
6+
// API KEY should be entered in the script settings in QuickAdd plugin options.
7+
const API_URL = "https://www.googleapis.com/books/v1/volumes";
8+
const API_KEY = "Google Books API Key"
9+
const GOODREADS_URL = "https://www.goodreads.com/search?qid=&q="
10+
11+
module.exports = {
12+
entry: start,
13+
settings: {
14+
name: "Books script",
15+
author: "Elaws",
16+
options: {
17+
[API_KEY]: {
18+
type: "text",
19+
defaultValue: "",
20+
placeholder: "Google Books API Key",
21+
}
22+
},
23+
},
24+
};
25+
26+
let QuickAdd;
27+
let Settings;
28+
29+
async function start(params, settings) {
30+
QuickAdd = params;
31+
Settings = settings;
32+
33+
var author;
34+
35+
// Possible to enter a book title or ISBN.
36+
var query = await QuickAdd.quickAddApi.inputPrompt(
37+
"Book title or ISBN: "
38+
);
39+
40+
// If no ISBN is entered, a prompt asks author name.
41+
// Possible to enter only author name, and no book title at previous step.
42+
if(!isISBN(query)){
43+
author = await QuickAdd.quickAddApi.inputPrompt(
44+
"Author: "
45+
);
46+
}
47+
48+
if(author) {
49+
if(!query){
50+
query = `inauthor:${author}`;
51+
} else {
52+
query = query.concat(" inauthor:", author);
53+
}
54+
}
55+
56+
if (!query) {
57+
notice("No query entered.");
58+
throw new Error("No query entered.");
59+
}
60+
61+
log(query);
62+
63+
const searchResults = await getByQuery(query);
64+
65+
const selection = await QuickAdd.quickAddApi.suggester(
66+
searchResults.map(formatTitleForSuggestion),
67+
searchResults
68+
);
69+
if (!selection) {
70+
notice("No choice selected.");
71+
throw new Error("No choice selected.");
72+
}
73+
74+
const selectedBook = selection.volumeInfo;
75+
76+
const ISBN = getISBN(selectedBook);
77+
78+
const isRead = await QuickAdd.quickAddApi.yesNoPrompt("Read ?");
79+
let myRating = "/10";
80+
let myRecommender = " ";
81+
let comment = " ";
82+
83+
// If book already read, add a rating to it.
84+
if(isRead){
85+
myRating = await QuickAdd.quickAddApi.inputPrompt("Rating", null, "/10");
86+
}
87+
88+
myRecommender = await QuickAdd.quickAddApi.inputPrompt("Recommender", null, " ");
89+
comment = await QuickAdd.quickAddApi.inputPrompt("Comment", null, " ");
90+
91+
QuickAdd.variables = {
92+
...selectedBook,
93+
fileName: replaceIllegalFileNameCharactersInString(selectedBook.title),
94+
authors: formatList(selectedBook.authors),
95+
isbn10: `${ISBN.ISBN10 ? ISBN.ISBN10 : " "}`,
96+
isbn13: `${ISBN.ISBN13 ? ISBN.ISBN13 : " "}`,
97+
// An URL to the GoodReads page of the book using its ISBN.
98+
// May fail if ISBN returned by Google Books is not in Goodreads database.
99+
goodreadsURL: `${ISBN.ISBN13 ? GOODREADS_URL + ISBN.ISBN13 : (ISBN.ISBN10 ? GOODREADS_URL + ISBN.ISBN10 : " ")}`,
100+
thumbnail: `${selectedBook.imageLinks ? selectedBook.imageLinks.thumbnail : " "}`.replace("http:", "https:"),
101+
// Publication date
102+
release: `${selectedBook.publishedDate ? (new Date((selectedBook.publishedDate))).getFullYear() : " "}`,
103+
// Squares of different color to tag Obsidian's note, depending if book has already been read or not.
104+
tag: `${isRead ? "\u{0001F7E7}" : "\u{0001F7E5}"}`,
105+
// A rating for the read book, /10.
106+
rating: myRating,
107+
// Is the book already read ? 1 if yes, 0 otherwise.
108+
read: `${isRead ? "1" : "0"}`,
109+
// Who recommended the book to me?
110+
recommender: myRecommender,
111+
// A short personal comment on the book.
112+
comment
113+
};
114+
}
115+
116+
function getISBN(item){
117+
118+
var ISBN10 = " ";
119+
var ISBN13 = " ";
120+
var isbn10_data, isbn13_data;
121+
122+
if(item.industryIdentifiers)
123+
{
124+
isbn10_data = (item.industryIdentifiers).find(element => element.type == "ISBN_10");
125+
isbn13_data = (item.industryIdentifiers).find(element => element.type == "ISBN_13");
126+
}
127+
128+
if(isbn10_data) ISBN10 = isbn10_data.identifier;
129+
if(isbn13_data) ISBN13 = isbn13_data.identifier;
130+
131+
return {ISBN10, ISBN13};
132+
}
133+
134+
function isISBN(str){
135+
return /^(97(8|9))?\d{9}(\d|X)$/.test(str);
136+
}
137+
138+
// Suggestion prompt will include :
139+
// (i) prefix if a book cover is available (i for "image")
140+
// Book's title
141+
// Book's author
142+
// Publication year
143+
function formatTitleForSuggestion(resultItem){
144+
return `${
145+
resultItem.volumeInfo.imageLinks ? "(i)" : ""
146+
} ${
147+
resultItem.volumeInfo.title} - ${
148+
resultItem.volumeInfo.authors ? resultItem.volumeInfo.authors[0] : ""
149+
} (${
150+
(new Date(resultItem.volumeInfo.publishedDate)).getFullYear()
151+
})`;
152+
}
153+
154+
async function getByQuery(query) {
155+
156+
const searchResults = await apiGet(query);
157+
158+
if(searchResults.error)
159+
{
160+
notice("Request failed");
161+
throw new Error("Request failed");
162+
}
163+
164+
if (searchResults.totalItems == 0) {
165+
notice("No results found.");
166+
throw new Error("No results found.");
167+
}
168+
169+
return searchResults.items;
170+
}
171+
172+
function formatList(list) {
173+
if (list.length === 0 || list[0] == "N/A") return " ";
174+
if (list.length === 1) return `${list[0]}`;
175+
176+
return list.map((item) => `\"${item.trim()}\"`).join(", ");
177+
}
178+
179+
function replaceIllegalFileNameCharactersInString(string) {
180+
return string.replace(/[\\,#%&\{\}\/*<>$\":@.]*/g, "");
181+
}
182+
183+
async function apiGet(query) {
184+
185+
let finalURL = new URL(API_URL);
186+
187+
finalURL.searchParams.append("q", query);
188+
finalURL.searchParams.append("key", Settings[API_KEY]);
189+
190+
log(finalURL.href);
191+
192+
const res = await request({
193+
url: finalURL.href,
194+
method: 'GET',
195+
cache: 'no-cache',
196+
})
197+
198+
return JSON.parse(res);
199+
}

0 commit comments

Comments
 (0)