mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-03-05 00:18:30 +01:00
Add:Global library search also searches on podcast episode titles #1363
This commit is contained in:
parent
88bd51e2da
commit
1609f1a499
0
client/components/cards/EpisodeSearchCard.vue
Normal file
0
client/components/cards/EpisodeSearchCard.vue
Normal 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>`
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user