diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue
index 41b73310..955e18d9 100644
--- a/client/components/cards/LazyBookCard.vue
+++ b/client/components/cards/LazyBookCard.vue
@@ -101,7 +101,8 @@
- Episode #{{ recentEpisodeNumber }}
+ Episode
+ #{{ recentEpisodeNumber }}
@@ -200,6 +201,9 @@ export default {
dateFormat() {
return this.store.getters['getServerSetting']('dateFormat')
},
+ timeFormat() {
+ return this.store.getters['getServerSetting']('timeFormat')
+ },
_libraryItem() {
return this.libraryItem || {}
},
@@ -345,6 +349,10 @@ export default {
if (this.mediaMetadata.publishedYear) return this.$getString('LabelPublishedDate', [this.mediaMetadata.publishedYear])
return '\u00A0'
}
+ if (this.orderBy === 'progress') {
+ if (!this.userProgressLastUpdated) return '\u00A0'
+ return this.$getString('LabelLastProgressDate', [this.$formatDatetime(this.userProgressLastUpdated, this.dateFormat, this.timeFormat)])
+ }
return null
},
episodeProgress() {
@@ -377,6 +385,10 @@ export default {
let progressPercent = this.itemIsFinished ? 1 : this.booksInSeries ? this.seriesProgressPercent : this.useEBookProgress ? this.userProgress?.ebookProgress || 0 : this.userProgress?.progress || 0
return Math.max(Math.min(1, progressPercent), 0)
},
+ userProgressLastUpdated() {
+ if (!this.userProgress) return null
+ return this.userProgress.lastUpdate
+ },
itemIsFinished() {
if (this.booksInSeries) return this.seriesIsFinished
return this.userProgress ? !!this.userProgress.isFinished : false
diff --git a/client/components/controls/LibrarySortSelect.vue b/client/components/controls/LibrarySortSelect.vue
index 7e83928f..facd62c0 100644
--- a/client/components/controls/LibrarySortSelect.vue
+++ b/client/components/controls/LibrarySortSelect.vue
@@ -130,6 +130,10 @@ export default {
text: this.$strings.LabelFileModified,
value: 'mtimeMs'
},
+ {
+ text: this.$strings.LabelLibrarySortByProgress,
+ value: 'progress'
+ },
{
text: this.$strings.LabelRandomly,
value: 'random'
diff --git a/client/store/user.js b/client/store/user.js
index a67eae34..158ec8f4 100644
--- a/client/store/user.js
+++ b/client/store/user.js
@@ -92,7 +92,7 @@ export const actions = {
if (state.settings.orderBy == 'media.duration') {
settingsUpdate.orderBy = 'media.numTracks'
}
- if (state.settings.orderBy == 'media.metadata.publishedYear') {
+ if (state.settings.orderBy == 'media.metadata.publishedYear' || state.settings.orderBy == 'progress') {
settingsUpdate.orderBy = 'media.metadata.title'
}
const invalidFilters = ['series', 'authors', 'narrators', 'publishers', 'publishedDecades', 'languages', 'progress', 'issues', 'ebooks', 'abridged']
diff --git a/client/strings/en-us.json b/client/strings/en-us.json
index 84cddb66..6dba7adb 100644
--- a/client/strings/en-us.json
+++ b/client/strings/en-us.json
@@ -418,6 +418,7 @@
"LabelLanguages": "Languages",
"LabelLastBookAdded": "Last Book Added",
"LabelLastBookUpdated": "Last Book Updated",
+ "LabelLastProgressDate": "Last progress: {0}",
"LabelLastSeen": "Last Seen",
"LabelLastTime": "Last Time",
"LabelLastUpdate": "Last Update",
@@ -430,6 +431,7 @@
"LabelLibraryFilterSublistEmpty": "No {0}",
"LabelLibraryItem": "Library Item",
"LabelLibraryName": "Library Name",
+ "LabelLibrarySortByProgress": "Progress Updated",
"LabelLimit": "Limit",
"LabelLineSpacing": "Line spacing",
"LabelListenAgain": "Listen Again",
diff --git a/server/utils/queries/libraryItemsBookFilters.js b/server/utils/queries/libraryItemsBookFilters.js
index ded712cf..85d7f387 100644
--- a/server/utils/queries/libraryItemsBookFilters.js
+++ b/server/utils/queries/libraryItemsBookFilters.js
@@ -399,9 +399,6 @@ module.exports = {
if (filterGroup !== 'series' && sortBy === 'sequence') {
sortBy = 'media.metadata.title'
}
- if (filterGroup !== 'progress' && sortBy === 'progress') {
- sortBy = 'media.metadata.title'
- }
const includeRSSFeed = include.includes('rssfeed')
const includeMediaItemShare = !!user?.isAdminOrUp && include.includes('share')
@@ -532,6 +529,18 @@ module.exports = {
}
}
+ // When sorting by progress but not filtering by progress, include media progresses
+ if (filterGroup !== 'progress' && sortBy === 'progress') {
+ bookIncludes.push({
+ model: Database.mediaProgressModel,
+ attributes: ['id', 'isFinished', 'currentTime', 'ebookProgress', 'updatedAt'],
+ where: {
+ userId: user.id
+ },
+ required: false
+ })
+ }
+
let { mediaWhere, replacements } = this.getMediaGroupQuery(filterGroup, filterValue)
let bookWhere = Array.isArray(mediaWhere) ? mediaWhere : [mediaWhere]