mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-03-05 00:18:30 +01:00
Add:Random library sorting option for libraries and series #3166
- Fixed author sort and match button not showing
This commit is contained in:
parent
82f136ba79
commit
43d6c6678f
@ -84,11 +84,6 @@
|
|||||||
|
|
||||||
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" />
|
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" />
|
||||||
</template>
|
</template>
|
||||||
<!-- home page -->
|
|
||||||
<template v-else-if="isHome">
|
|
||||||
<div class="flex-grow" />
|
|
||||||
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" />
|
|
||||||
</template>
|
|
||||||
<!-- search page -->
|
<!-- search page -->
|
||||||
<template v-else-if="page === 'search'">
|
<template v-else-if="page === 'search'">
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
@ -99,10 +94,15 @@
|
|||||||
<!-- authors page -->
|
<!-- authors page -->
|
||||||
<template v-else-if="page === 'authors'">
|
<template v-else-if="page === 'authors'">
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-if="userCanUpdate && authors && authors.length && !isBatchSelecting" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn>
|
<ui-btn v-if="userCanUpdate && authors?.length && !isBatchSelecting" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn>
|
||||||
|
|
||||||
<!-- author sort select -->
|
<!-- author sort select -->
|
||||||
<controls-sort-select v-if="authors && authors.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" />
|
<controls-sort-select v-if="authors?.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" />
|
||||||
|
</template>
|
||||||
|
<!-- home page -->
|
||||||
|
<template v-else-if="isHome">
|
||||||
|
<div class="flex-grow" />
|
||||||
|
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -187,6 +187,10 @@ export default {
|
|||||||
{
|
{
|
||||||
text: this.$strings.LabelTotalDuration,
|
text: this.$strings.LabelTotalDuration,
|
||||||
value: 'totalDuration'
|
value: 'totalDuration'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelRandomly,
|
||||||
|
value: 'random'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -88,6 +88,10 @@ export default {
|
|||||||
{
|
{
|
||||||
text: this.$strings.LabelFileModified,
|
text: this.$strings.LabelFileModified,
|
||||||
value: 'mtimeMs'
|
value: 'mtimeMs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelRandomly,
|
||||||
|
value: 'random'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -128,6 +132,10 @@ export default {
|
|||||||
{
|
{
|
||||||
text: this.$strings.LabelFileModified,
|
text: this.$strings.LabelFileModified,
|
||||||
value: 'mtimeMs'
|
value: 'mtimeMs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelRandomly,
|
||||||
|
value: 'random'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -455,6 +455,7 @@
|
|||||||
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
||||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||||
"LabelRSSFeedURL": "RSS Feed URL",
|
"LabelRSSFeedURL": "RSS Feed URL",
|
||||||
|
"LabelRandomly": "Randomly",
|
||||||
"LabelReAddSeriesToContinueListening": "Re-add series to Continue Listening",
|
"LabelReAddSeriesToContinueListening": "Re-add series to Continue Listening",
|
||||||
"LabelRead": "Read",
|
"LabelRead": "Read",
|
||||||
"LabelReadAgain": "Read Again",
|
"LabelReadAgain": "Read Again",
|
||||||
|
@ -2,7 +2,6 @@ const Sequelize = require('sequelize')
|
|||||||
const Database = require('../../Database')
|
const Database = require('../../Database')
|
||||||
const Logger = require('../../Logger')
|
const Logger = require('../../Logger')
|
||||||
const authorFilters = require('./authorFilters')
|
const authorFilters = require('./authorFilters')
|
||||||
const { asciiOnlyToLowerCase } = require('../index')
|
|
||||||
|
|
||||||
const ShareManager = require('../../managers/ShareManager')
|
const ShareManager = require('../../managers/ShareManager')
|
||||||
|
|
||||||
@ -274,6 +273,8 @@ module.exports = {
|
|||||||
return [[Sequelize.literal(`CAST(\`series.bookSeries.sequence\` AS FLOAT) ${nullDir}`)]]
|
return [[Sequelize.literal(`CAST(\`series.bookSeries.sequence\` AS FLOAT) ${nullDir}`)]]
|
||||||
} else if (sortBy === 'progress') {
|
} else if (sortBy === 'progress') {
|
||||||
return [[Sequelize.literal('mediaProgresses.updatedAt'), dir]]
|
return [[Sequelize.literal('mediaProgresses.updatedAt'), dir]]
|
||||||
|
} else if (sortBy === 'random') {
|
||||||
|
return [Database.sequelize.random()]
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
|
@ -89,6 +89,8 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
} else if (sortBy === 'media.numTracks') {
|
} else if (sortBy === 'media.numTracks') {
|
||||||
return [['numEpisodes', dir]]
|
return [['numEpisodes', dir]]
|
||||||
|
} else if (sortBy === 'random') {
|
||||||
|
return [Database.sequelize.random()]
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
|
@ -26,7 +26,7 @@ module.exports = {
|
|||||||
let filterGroup = null
|
let filterGroup = null
|
||||||
if (filterBy) {
|
if (filterBy) {
|
||||||
const searchGroups = ['genres', 'tags', 'authors', 'progress', 'narrators', 'publishers', 'languages']
|
const searchGroups = ['genres', 'tags', 'authors', 'progress', 'narrators', 'publishers', 'languages']
|
||||||
const group = searchGroups.find(_group => filterBy.startsWith(_group + '.'))
|
const group = searchGroups.find((_group) => filterBy.startsWith(_group + '.'))
|
||||||
filterGroup = group || filterBy
|
filterGroup = group || filterBy
|
||||||
filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null
|
filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null
|
||||||
}
|
}
|
||||||
@ -49,9 +49,11 @@ module.exports = {
|
|||||||
// Handle library setting to hide single book series
|
// Handle library setting to hide single book series
|
||||||
// TODO: Merge with existing query
|
// TODO: Merge with existing query
|
||||||
if (library.settings.hideSingleBookSeries) {
|
if (library.settings.hideSingleBookSeries) {
|
||||||
seriesWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), {
|
seriesWhere.push(
|
||||||
[Sequelize.Op.gt]: 1
|
Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), {
|
||||||
}))
|
[Sequelize.Op.gt]: 1
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle filters
|
// Handle filters
|
||||||
@ -101,9 +103,11 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attrQuery) {
|
if (attrQuery) {
|
||||||
seriesWhere.push(Sequelize.where(Sequelize.literal(`(${attrQuery})`), {
|
seriesWhere.push(
|
||||||
[Sequelize.Op.gt]: 0
|
Sequelize.where(Sequelize.literal(`(${attrQuery})`), {
|
||||||
}))
|
[Sequelize.Op.gt]: 0
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const order = []
|
const order = []
|
||||||
@ -133,6 +137,8 @@ module.exports = {
|
|||||||
} else if (sortBy === 'lastBookUpdated') {
|
} else if (sortBy === 'lastBookUpdated') {
|
||||||
seriesAttributes.include.push([Sequelize.literal('(SELECT MAX(b.updatedAt) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND b.id = bs.bookId)'), 'mostRecentBookUpdated'])
|
seriesAttributes.include.push([Sequelize.literal('(SELECT MAX(b.updatedAt) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND b.id = bs.bookId)'), 'mostRecentBookUpdated'])
|
||||||
order.push(['mostRecentBookUpdated', dir])
|
order.push(['mostRecentBookUpdated', dir])
|
||||||
|
} else if (sortBy === 'random') {
|
||||||
|
order.push(Database.sequelize.random())
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
|
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
|
||||||
@ -184,7 +190,7 @@ module.exports = {
|
|||||||
sensitivity: 'base'
|
sensitivity: 'base'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
oldSeries.books = s.bookSeries.map(bs => {
|
oldSeries.books = s.bookSeries.map((bs) => {
|
||||||
const libraryItem = bs.book.libraryItem.toJSON()
|
const libraryItem = bs.book.libraryItem.toJSON()
|
||||||
delete bs.book.libraryItem
|
delete bs.book.libraryItem
|
||||||
libraryItem.media = bs.book
|
libraryItem.media = bs.book
|
||||||
|
Loading…
Reference in New Issue
Block a user