Add:Global library search also searches on podcast episode titles #1363

This commit is contained in:
advplyr 2023-01-04 17:43:15 -06:00
parent 88bd51e2da
commit 1609f1a499
7 changed files with 45 additions and 20 deletions

View File

@ -10,7 +10,7 @@
<p v-if="matchKey !== 'authors'" class="text-xs text-gray-200 truncate">by {{ authorName }}</p> <p v-if="matchKey !== 'authors'" class="text-xs text-gray-200 truncate">by {{ authorName }}</p>
<p v-else class="truncate text-xs text-gray-200" v-html="matchHtml" /> <p v-else class="truncate text-xs text-gray-200" v-html="matchHtml" />
<div v-if="matchKey === 'series' || matchKey === 'tags' || matchKey === 'isbn' || matchKey === 'asin'" class="m-0 p-0 truncate text-xs" v-html="matchHtml" /> <div v-if="matchKey === 'series' || matchKey === 'tags' || matchKey === 'isbn' || matchKey === 'asin' || matchKey === 'episode'" class="m-0 p-0 truncate text-xs" v-html="matchHtml" />
</div> </div>
</div> </div>
</template> </template>
@ -67,6 +67,7 @@ export default {
// but with removing commas periods etc this is no longer plausible // but with removing commas periods etc this is no longer plausible
const html = this.matchText const html = this.matchText
if (this.matchKey === 'episode') return `<p class="truncate">Episode: ${html}</p>`
if (this.matchKey === 'tags') return `<p class="truncate">Tags: ${html}</p>` if (this.matchKey === 'tags') return `<p class="truncate">Tags: ${html}</p>`
if (this.matchKey === 'authors') return `by ${html}` if (this.matchKey === 'authors') return `by ${html}`
if (this.matchKey === 'isbn') return `<p class="truncate">ISBN: ${html}</p>` if (this.matchKey === 'isbn') return `<p class="truncate">ISBN: ${html}</p>`

View File

@ -572,16 +572,16 @@ class LibraryController {
if (!req.query.q) { if (!req.query.q) {
return res.status(400).send('No query string') return res.status(400).send('No query string')
} }
var libraryItems = req.libraryItems const libraryItems = req.libraryItems
var maxResults = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12 const maxResults = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12
var itemMatches = [] const itemMatches = []
var authorMatches = {} const authorMatches = {}
var seriesMatches = {} const seriesMatches = {}
var tagMatches = {} const tagMatches = {}
libraryItems.forEach((li) => { libraryItems.forEach((li) => {
var queryResult = li.searchQuery(req.query.q) const queryResult = li.searchQuery(req.query.q)
if (queryResult.matchKey) { if (queryResult.matchKey) {
itemMatches.push({ itemMatches.push({
libraryItem: li.toJSONExpanded(), libraryItem: li.toJSONExpanded(),
@ -592,7 +592,7 @@ class LibraryController {
if (queryResult.series && queryResult.series.length) { if (queryResult.series && queryResult.series.length) {
queryResult.series.forEach((se) => { queryResult.series.forEach((se) => {
if (!seriesMatches[se.id]) { if (!seriesMatches[se.id]) {
var _series = this.db.series.find(_se => _se.id === se.id) const _series = this.db.series.find(_se => _se.id === se.id)
if (_series) seriesMatches[se.id] = { series: _series.toJSON(), books: [li.toJSON()] } if (_series) seriesMatches[se.id] = { series: _series.toJSON(), books: [li.toJSON()] }
} else { } else {
seriesMatches[se.id].books.push(li.toJSON()) seriesMatches[se.id].books.push(li.toJSON())
@ -602,7 +602,7 @@ class LibraryController {
if (queryResult.authors && queryResult.authors.length) { if (queryResult.authors && queryResult.authors.length) {
queryResult.authors.forEach((au) => { queryResult.authors.forEach((au) => {
if (!authorMatches[au.id]) { if (!authorMatches[au.id]) {
var _author = this.db.authors.find(_au => _au.id === au.id) const _author = this.db.authors.find(_au => _au.id === au.id)
if (_author) { if (_author) {
authorMatches[au.id] = _author.toJSON() authorMatches[au.id] = _author.toJSON()
authorMatches[au.id].numBooks = 1 authorMatches[au.id].numBooks = 1
@ -622,8 +622,8 @@ class LibraryController {
}) })
} }
}) })
var itemKey = req.library.mediaType const itemKey = req.library.mediaType
var results = { const results = {
[itemKey]: itemMatches.slice(0, maxResults), [itemKey]: itemMatches.slice(0, maxResults),
tags: Object.values(tagMatches).slice(0, maxResults), tags: Object.values(tagMatches).slice(0, maxResults),
authors: Object.values(authorMatches).slice(0, maxResults), authors: Object.values(authorMatches).slice(0, maxResults),

View File

@ -1,5 +1,5 @@
const Path = require('path') const Path = require('path')
const { getId } = require('../../utils/index') const { getId, cleanStringForSearch } = require('../../utils/index')
const AudioFile = require('../files/AudioFile') const AudioFile = require('../files/AudioFile')
const AudioTrack = require('../files/AudioTrack') const AudioTrack = require('../files/AudioTrack')
@ -160,5 +160,9 @@ class PodcastEpisode {
if (!this.enclosure || !this.enclosure.url) return false if (!this.enclosure || !this.enclosure.url) return false
return this.enclosure.url == url return this.enclosure.url == url
} }
searchQuery(query) {
return cleanStringForSearch(this.title).includes(query)
}
} }
module.exports = PodcastEpisode module.exports = PodcastEpisode

View File

@ -311,14 +311,14 @@ class Book {
} }
searchQuery(query) { searchQuery(query) {
var payload = { const payload = {
tags: this.tags.filter(t => cleanStringForSearch(t).includes(query)), tags: this.tags.filter(t => cleanStringForSearch(t).includes(query)),
series: this.metadata.searchSeries(query), series: this.metadata.searchSeries(query),
authors: this.metadata.searchAuthors(query), authors: this.metadata.searchAuthors(query),
matchKey: null, matchKey: null,
matchText: null matchText: null
} }
var metadataMatch = this.metadata.searchQuery(query) const metadataMatch = this.metadata.searchQuery(query)
if (metadataMatch) { if (metadataMatch) {
payload.matchKey = metadataMatch.matchKey payload.matchKey = metadataMatch.matchKey
payload.matchText = metadataMatch.matchText payload.matchText = metadataMatch.matchText

View File

@ -1,7 +1,7 @@
const Logger = require('../../Logger') const Logger = require('../../Logger')
const PodcastEpisode = require('../entities/PodcastEpisode') const PodcastEpisode = require('../entities/PodcastEpisode')
const PodcastMetadata = require('../metadata/PodcastMetadata') const PodcastMetadata = require('../metadata/PodcastMetadata')
const { areEquivalent, copyValue } = require('../../utils/index') const { areEquivalent, copyValue, cleanStringForSearch } = require('../../utils/index')
const abmetadataGenerator = require('../../utils/abmetadataGenerator') const abmetadataGenerator = require('../../utils/abmetadataGenerator')
const { readTextFile } = require('../../utils/fileUtils') const { readTextFile } = require('../../utils/fileUtils')
const { createNewSortInstance } = require('../../libs/fastSort') const { createNewSortInstance } = require('../../libs/fastSort')
@ -206,9 +206,29 @@ class Podcast {
return false return false
} }
searchEpisodes(query) {
return this.episodes.filter(ep => ep.searchQuery(query))
}
searchQuery(query) { searchQuery(query) {
var payload = this.metadata.searchQuery(query) const payload = {
return payload || {} tags: this.tags.filter(t => cleanStringForSearch(t).includes(query)),
matchKey: null,
matchText: null
}
const metadataMatch = this.metadata.searchQuery(query)
if (metadataMatch) {
payload.matchKey = metadataMatch.matchKey
payload.matchText = metadataMatch.matchText
} else {
const matchingEpisodes = this.searchEpisodes(query)
if (matchingEpisodes.length) {
payload.matchKey = 'episode'
payload.matchText = matchingEpisodes[0].title
}
}
return payload
} }
checkHasEpisode(episodeId) { checkHasEpisode(episodeId) {

View File

@ -377,8 +377,8 @@ class BookMetadata {
return this.authors.filter(au => cleanStringForSearch(au.name).includes(query)) return this.authors.filter(au => cleanStringForSearch(au.name).includes(query))
} }
searchQuery(query) { // Returns key if match is found searchQuery(query) { // Returns key if match is found
var keysToCheck = ['title', 'asin', 'isbn'] const keysToCheck = ['title', 'asin', 'isbn']
for (var key of keysToCheck) { for (const key of keysToCheck) {
if (this[key] && cleanStringForSearch(String(this[key])).includes(query)) { if (this[key] && cleanStringForSearch(String(this[key])).includes(query)) {
return { return {
matchKey: key, matchKey: key,