Merge branch 'advplyr:master' into audible-confidence-score

This commit is contained in:
mikiher 2025-06-26 18:09:13 +03:00 committed by GitHub
commit 9c44fc0d01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 187 additions and 65 deletions

View file

@ -25,6 +25,7 @@ const Fuse = require('../libs/fusejs')
* @property {string} episode
* @property {string} author
* @property {string} duration
* @property {number|null} durationSeconds - Parsed from duration string if duration is valid
* @property {string} explicit
* @property {number} publishedAt - Unix timestamp
* @property {{ url: string, type?: string, length?: string }} enclosure
@ -217,8 +218,9 @@ function extractEpisodeData(item) {
})
// Extract psc:chapters if duration is set
let episodeDuration = !isNaN(episode.duration) ? timestampToSeconds(episode.duration) : null
if (item['psc:chapters']?.[0]?.['psc:chapter']?.length && episodeDuration) {
episode.durationSeconds = episode.duration ? timestampToSeconds(episode.duration) : null
if (item['psc:chapters']?.[0]?.['psc:chapter']?.length && episode.durationSeconds) {
// Example chapter:
// {"id":0,"start":0,"end":43.004286,"title":"chapter 1"}
@ -244,7 +246,7 @@ function extractEpisodeData(item) {
} else {
episode.chapters = cleanedChapters.map((chapter, index) => {
const nextChapter = cleanedChapters[index + 1]
const end = nextChapter ? nextChapter.start : episodeDuration
const end = nextChapter ? nextChapter.start : episode.durationSeconds
return {
id: chapter.id,
title: chapter.title,
@ -273,6 +275,7 @@ function cleanEpisodeData(data) {
episode: data.episode || '',
author: data.author || '',
duration: data.duration || '',
durationSeconds: data.durationSeconds || null,
explicit: data.explicit || '',
publishedAt,
enclosure: data.enclosure,

View file

@ -186,6 +186,8 @@ module.exports = {
mediaWhere['$series.id$'] = null
} else if (group === 'abridged') {
mediaWhere['abridged'] = true
} else if (group === 'explicit') {
mediaWhere['explicit'] = true
} else if (['genres', 'tags', 'narrators'].includes(group)) {
mediaWhere[group] = Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(${group}) WHERE json_valid(${group}) AND json_each.value = :filterValue)`), {
[Sequelize.Op.gte]: 1
@ -251,6 +253,15 @@ module.exports = {
*/
getOrder(sortBy, sortDesc, collapseseries) {
const dir = sortDesc ? 'DESC' : 'ASC'
const getTitleOrder = () => {
if (global.ServerSettings.sortingIgnorePrefix) {
return [Sequelize.literal('`libraryItem`.`titleIgnorePrefix` COLLATE NOCASE'), dir]
} else {
return [Sequelize.literal('`libraryItem`.`title` COLLATE NOCASE'), dir]
}
}
if (sortBy === 'addedAt') {
return [[Sequelize.literal('libraryItem.createdAt'), dir]]
} else if (sortBy === 'size') {
@ -264,25 +275,16 @@ module.exports = {
} else if (sortBy === 'media.metadata.publishedYear') {
return [[Sequelize.literal(`CAST(\`book\`.\`publishedYear\` AS INTEGER)`), dir]]
} else if (sortBy === 'media.metadata.authorNameLF') {
return [
[Sequelize.literal('`libraryItem`.`authorNamesLastFirst` COLLATE NOCASE'), dir],
[Sequelize.literal('`libraryItem`.`title` COLLATE NOCASE'), dir]
]
// Sort by author name last first, secondary sort by title
return [[Sequelize.literal('`libraryItem`.`authorNamesLastFirst` COLLATE NOCASE'), dir], getTitleOrder()]
} else if (sortBy === 'media.metadata.authorName') {
return [
[Sequelize.literal('`libraryItem`.`authorNamesFirstLast` COLLATE NOCASE'), dir],
[Sequelize.literal('`libraryItem`.`title` COLLATE NOCASE'), dir]
]
// Sort by author name first last, secondary sort by title
return [[Sequelize.literal('`libraryItem`.`authorNamesFirstLast` COLLATE NOCASE'), dir], getTitleOrder()]
} else if (sortBy === 'media.metadata.title') {
if (collapseseries) {
return [[Sequelize.literal('display_title COLLATE NOCASE'), dir]]
}
if (global.ServerSettings.sortingIgnorePrefix) {
return [[Sequelize.literal('`libraryItem`.`titleIgnorePrefix` COLLATE NOCASE'), dir]]
} else {
return [[Sequelize.literal('`libraryItem`.`title` COLLATE NOCASE'), dir]]
}
return [getTitleOrder()]
} else if (sortBy === 'sequence') {
const nullDir = sortDesc ? 'DESC NULLS FIRST' : 'ASC NULLS LAST'
return [[Sequelize.literal(`CAST(\`series.bookSeries.sequence\` AS FLOAT) ${nullDir}`)]]

View file

@ -59,6 +59,8 @@ module.exports = {
replacements.filterValue = value
} else if (group === 'languages') {
mediaWhere['language'] = value
} else if (group === 'explicit') {
mediaWhere['explicit'] = true
}
return {