diff --git a/package.json b/package.json index 6158278..bc966ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ztimson/zim-utils", - "version": "0.4.1", + "version": "0.4.2", "description": "Native, dependency-light ZIM archive reader/searcher and Kiwix catalog downloader for Node.js", "author": "Zak Timson", "license": "MIT", diff --git a/src/search.js b/src/search.js index 419a4b3..1f8e5f4 100644 --- a/src/search.js +++ b/src/search.js @@ -101,7 +101,7 @@ export function rerank(hits, termList) { const title = fieldScore(hit.title, termList, {fuzzy: true}); const summary = fieldScore(hit.summary, termList); const titleLower = (hit.title || '').toLowerCase(); - const summaryLower = (hit.summary || '').toLowerCase(); + const summaryLower = (hit.summary?._text || '').toLowerCase(); const phrase = termList.join(' ').toLowerCase(); const titleExactPhrase = titleLower.includes(phrase) ? 1 : 0; diff --git a/src/server.js b/src/server.js index 62bac2b..8a42a94 100644 --- a/src/server.js +++ b/src/server.js @@ -212,7 +212,7 @@ export class KiwixServer { return makeArray(entries?.library?.book || []).map(e => { const tags = e.tags.split(';'); - const name = e.path.replace('.zim', ''); + const name = e.path.replace(/\.zim$/i, ''); return { id: e.id, @@ -262,53 +262,43 @@ export class KiwixServer { } async #rawSearch(termList, scoped, bookMap, limit) { - const groups = new Map(); - - for(const book of scoped) { - const lang = book.language || ''; - (groups.get(lang) ?? groups.set(lang, []).get(lang)).push(book); - } - - const perGroup = await Promise.all([...groups.values()].map(async group => { + const perBook = await Promise.all(scoped.map(async book => { const params = new URLSearchParams({ pattern: termList.join(' '), format: 'xml', pageLength: String(limit), + 'books.name': book.href, }); - for(const book of group) - params.append('books.name', book.name); - const res = await fetch(`${this.baseUrl}/search?${params}`); if(!res.ok) return []; const found = fromXml(await res.text())?.rss?.channel?.item || []; return found.map(hit => { - const book = bookMap.get(hit.book.title); - if(!book) return null; + const resultBook = bookMap.get(hit.book?.title) || book; - const prefix = `/content/${book.href}/`; + const prefix = `/content/${resultBook.href}/`; const page = hit.link.startsWith(prefix) ? hit.link.slice(prefix.length) : hit.link.replace(/^\/+/, ''); return { - id: book.id, + id: resultBook.id, title: hit.title, page, - name: book.name, - publisher: book.publisher, - href: `${book.href}/${page}`, - icon: book.icon, + name: resultBook.name, + publisher: resultBook.publisher, + href: `${resultBook.href}/${page}`, + icon: resultBook.icon, viewer: this.baseUrl + hit.link, summary: hit.description, xapianScore: +hit.score || 0, }; - }).filter(Boolean).sort((a, b) => b.xapianScore - a.xapianScore); + }).filter(Boolean); })); - return rrfMerge(perGroup); + return rrfMerge(perBook); } /** Fulltext search across local ZIMs with ranking, diversification and spelling correction. */ @@ -320,6 +310,7 @@ export class KiwixServer { const books = await this.list(); const bookMap = new Map(books.map(b => [b.title, b])); + const scoped = sources?.length ? books.filter(b => sources.includes(b.name) || sources.includes(b.href)) : books; @@ -360,8 +351,10 @@ export class KiwixServer { } } + const ranked = rerank(hits, activeTerms); + return { - results: diversify(rerank(hits, activeTerms), limit), + results: diversify(ranked, limit), spellcheck, }; }