diff --git a/app/views/search/controller.js b/app/views/search/controller.js
index e899f1d..c3c2255 100644
--- a/app/views/search/controller.js
+++ b/app/views/search/controller.js
@@ -53,7 +53,7 @@ export class SearchController extends ViewController {
const searchTerm = this.appState.query.for.trim();
- return fetch(`/api/search?for=${searchTerm}&lang=${this.appState.language}`)
+ return fetch(`/api/search?for=${searchTerm}&by=${this.state.searchBy}&lang=${this.appState.language}&source=${this.state.searchSource}`)
.then(response => response.json())
.then(responseJSON => {
this.state.results = responseJSON;
diff --git a/app/views/search/index.js b/app/views/search/index.js
index 3f05ec8..d22280f 100644
--- a/app/views/search/index.js
+++ b/app/views/search/index.js
@@ -94,10 +94,10 @@ export const searchView = (state, emit, i18n) => {
-
-
diff --git a/server/controllers/books.js b/server/controllers/books.js
index 727275b..c1137e2 100644
--- a/server/controllers/books.js
+++ b/server/controllers/books.js
@@ -1,8 +1,11 @@
const fetch = require('node-fetch');
class BooksController {
- constructor(inventaireDomain, bookURI, language) {
- this.inventaire = inventaireDomain;
+ constructor(bookSource, bookURI, language) {
+ this.source = bookSource;
+ this.inventaire = 'https://inventaire.io';
+ this.openLibrary = 'https://openlibrary.org';
+ this.bookBrainz = 'https://bookbrainz.org';
this.uri = bookURI;
this.lang = language;
}
@@ -87,7 +90,7 @@ class BooksController {
typeof entityObject.image !== 'undefined'
? entityObject.image.map(imageId => {
return {
- uri: imageId,
+ uri: imageId.toString(),
url: `${this.inventaire}/img/entities/${imageId}`,
}
})
@@ -132,6 +135,36 @@ class BooksController {
};
}
+ handleOpenLibraryEntity(entityObject) {
+ return {
+ name: (
+ typeof entityObject.title_suggest !== 'undefined'
+ ? entityObject.title_suggest
+ : null
+ ),
+ description: (
+ typeof entityObject.author_name !== 'undefined'
+ ? `${entityObject.type} by ${entityObject.author_name.map(name => name.trim()).join(', ')}`
+ : null
+ ),
+ link: (
+ typeof entityObject.key !== 'undefined'
+ ? `${this.openLibrary}${entityObject.key}`
+ : null
+ ),
+ uri: (
+ typeof entityObject.key !== 'undefined'
+ ? entityObject.key.substr(entityObject.key.lastIndexOf('/') + 1)
+ : null
+ ),
+ coverId: (
+ typeof entityObject.cover_i !== 'undefined'
+ ? entityObject.cover_i.toString()
+ : false
+ ),
+ };
+ }
+
async getBookDataFromInventaire() {
if (this.uri) {
const request = fetch(`${this.inventaire}/api/entities?action=by-uris&uris=${encodeURIComponent(this.uri)}`)
diff --git a/server/controllers/search.js b/server/controllers/search.js
index ff30ae0..90ee365 100644
--- a/server/controllers/search.js
+++ b/server/controllers/search.js
@@ -3,8 +3,7 @@ const fetch = require('node-fetch');
const BooksController = require('./books');
class SearchController {
- constructor(inventaireDomain, searchTerm, language = 'en') {
- this.inventaire = inventaireDomain;
+ constructor(searchTerm, language = 'en') {
this.term = searchTerm;
this.lang = language;
}
@@ -15,7 +14,7 @@ class SearchController {
quickSearchInventaire() {
if (this.hasQuery) {
- const request = fetch(`${this.inventaire}/api/search?types=works&search=${encodeURIComponent(this.term)}&lang=${encodeURIComponent(this.lang)}&limit=10`)
+ const request = fetch(`https://inventaire.io/api/search?types=works&search=${encodeURIComponent(this.term)}&lang=${encodeURIComponent(this.lang)}&limit=10`)
request.catch(exception => {
console.error(exception);
return {
@@ -32,9 +31,11 @@ class SearchController {
}
});
return json.then(responseJSON => {
+ const booksController = new BooksController('inventaire', undefined, this.lang);
+
return responseJSON.results.map(work => {
- const booksController = new BooksController(this.inventaire, work.uri, this.lang);
const bookData = booksController.handleQuickInventaireEntity(work);
+ booksController.uri = bookData.uri; // Update booksController.uri for each book when fetching community data.
const communityData = booksController.getCommunityData(5);
return {
@@ -46,9 +47,9 @@ class SearchController {
}
}
- searchInventaire() {
+ searchInventaire(searchBy = 'title') {
if (this.hasQuery) {
- const request = fetch(`${this.inventaire}/api/entities?action=search&search=${encodeURIComponent(this.term)}&lang=${encodeURIComponent(this.lang)}`)
+ const request = fetch(`https://inventaire.io/api/entities?action=search&search=${encodeURIComponent(this.term)}&lang=${encodeURIComponent(this.lang)}`)
request.catch(exception => {
console.error(exception);
return {
@@ -65,8 +66,8 @@ class SearchController {
}
});
return json.then(responseJSON => {
+ const booksController = new BooksController('inventaire', undefined, this.lang);
return responseJSON.works.map(work => {
- const booksController = new BooksController(this.inventaire, work.uri, this.lang);
const bookData = booksController.handleInventaireEntity(work);
const communityData = booksController.getCommunityData(5);
@@ -167,44 +168,56 @@ class SearchController {
});
}
- async searchOpenLibrary() {
+ async searchOpenLibrary(searchBy = 'title') {
if (!this.hasQuery) {
return [];
}
- return fetch('http://openlibrary.org/search.json?q=' + encodeURIComponent(this.term))
+ return fetch(`http://openlibrary.org/search.json?${searchBy}=${encodeURIComponent(this.term)}`)
.then(res => res.json())
.then(response => {
if (!response.hasOwnProperty('docs')) {
return [];
}
+
+ const booksController = new BooksController('openLibrary', undefined, this.lang);
+
// Format the response into usable objects
const docs = response.docs.map(doc => {
- return {
- title: doc.title_suggest.trim(),
- authors: doc.hasOwnProperty('author_name') ? doc.author_name.map(name => name.trim()) : [],
- cover: doc.hasOwnProperty('cover_i') ? `//covers.openlibrary.org/b/id/${doc.cover_i}-S.jpg` : false,
- };
+ return booksController.handleOpenLibraryEntity(doc);
});
// Filter out duplicate items with the same title and author
const results = docs.filter((doc, index, allDocs) => {
return typeof allDocs.find((filterResult, filterIndex) => {
return index !== filterIndex && filterResult.title === doc.title
- && JSON.stringify(filterResult.authors) === JSON.stringify(doc.authors);
+ && filterResult.description === doc.description;
}) === 'undefined';
}).map(result => {
// Find any duplicates in case they have different cover data
const duplicates = docs.filter(doc => {
- return doc.title.toLowerCase() === result.title.toLowerCase() && JSON.stringify(doc.authors) === JSON.stringify(result.authors);
+ return doc.name.toLowerCase() === result.name.toLowerCase() && doc.description === result.description;
});
result.covers = [];
duplicates.forEach(duplicate => {
- if (duplicate.cover !== false) {
- result.covers.push(duplicate.cover);
+ if (duplicate.coverId !== false) {
+ result.covers.push({
+ uri: duplicate.coverId,
+ url: `//covers.openlibrary.org/b/id/${duplicate.coverId}-M.jpg`,
+ });
}
});
+ delete result.coverId;
return result;
+ }).map(bookData => {
+ // Use bookController to get community data
+ booksController.uri = bookData.uri; // Update booksController.uri for each book when fetching community data.
+ const communityData = booksController.getCommunityData(5);
+
+ return {
+ ...bookData,
+ ...communityData,
+ };
});
return results;
diff --git a/server/routes/search.js b/server/routes/search.js
index 87cd520..89297fd 100644
--- a/server/routes/search.js
+++ b/server/routes/search.js
@@ -3,10 +3,27 @@ const SearchController = require('../controllers/search');
async function routes(fastify, options) {
fastify.get('/api/search', async (request, reply) => {
const searchTerm = typeof request.query.for !== 'undefined' ? request.query.for.trim() : '';
+ const searchBy = typeof request.query.by !== 'undefined' ? request.query.by.trim() : 'title';
const language = typeof request.query.lang !== 'undefined' ? request.query.lang.trim().split('-')[0] : undefined; // Get base language in cases like 'en-US'
- const search = new SearchController(fastify.siteConfig.inventaireDomain, searchTerm, language);
+ const searchSource = typeof request.query.source !== 'undefined' ? request.query.source.trim() : undefined; // Get base language in cases like 'en-US'
+ const search = new SearchController(searchTerm, language);
- return await search.quickSearchInventaire();
+ switch (searchSource) {
+ case 'openLibrary': {
+ return await search.searchOpenLibrary(searchBy);
+ }
+ case 'bookBrainz': {
+ return await search.searchOpenLibrary(searchBy);
+ }
+ case 'inventaire':
+ default: {
+ if (searchBy === 'title') {
+ return await search.quickSearchInventaire();
+ } else {
+ return await search.searchInventaire(searchBy);
+ }
+ }
+ }
});
fastify.get('/api/search/cover', async (request, reply) => {