mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-20 19:06:06 +01:00
Add:Library settings for mark as finished when time remaining or percent complete #837
This commit is contained in:
parent
6ca277a21d
commit
91aea4f754
@ -111,7 +111,6 @@ export default {
|
|||||||
},
|
},
|
||||||
updateLibrary(library) {
|
updateLibrary(library) {
|
||||||
this.mapLibraryToCopy(library)
|
this.mapLibraryToCopy(library)
|
||||||
console.log('Updated library', this.libraryCopy)
|
|
||||||
},
|
},
|
||||||
getNewLibraryData() {
|
getNewLibraryData() {
|
||||||
return {
|
return {
|
||||||
@ -128,7 +127,9 @@ export default {
|
|||||||
autoScanCronExpression: null,
|
autoScanCronExpression: null,
|
||||||
hideSingleBookSeries: false,
|
hideSingleBookSeries: false,
|
||||||
onlyShowLaterBooksInContinueSeries: false,
|
onlyShowLaterBooksInContinueSeries: false,
|
||||||
metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
|
metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata'],
|
||||||
|
markAsFinishedPercentComplete: null,
|
||||||
|
markAsFinishedTimeRemaining: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -236,7 +237,6 @@ export default {
|
|||||||
this.show = false
|
this.show = false
|
||||||
this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
|
this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
|
||||||
if (!this.$store.state.libraries.currentLibraryId) {
|
if (!this.$store.state.libraries.currentLibraryId) {
|
||||||
console.log('Setting initially library id', res.id)
|
|
||||||
// First library added
|
// First library added
|
||||||
this.$store.dispatch('libraries/fetch', res.id)
|
this.$store.dispatch('libraries/fetch', res.id)
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,20 @@
|
|||||||
<div v-if="isPodcastLibrary" class="p-2 w-full md:w-1/2">
|
<div v-if="isPodcastLibrary" class="p-2 w-full md:w-1/2">
|
||||||
<ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
|
<ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="p-2 w-full flex items-center space-x-2 flex-wrap">
|
||||||
|
<div>
|
||||||
|
<ui-dropdown v-model="markAsFinishedWhen" :items="maskAsFinishedWhenItems" :label="$strings.LabelSettingsLibraryMarkAsFinishedWhen" small class="w-72 min-w-72 text-sm" menu-max-height="200px" @input="markAsFinishedWhenChanged" />
|
||||||
|
</div>
|
||||||
|
<div class="w-16">
|
||||||
|
<div>
|
||||||
|
<label class="px-1 text-sm font-semibold"></label>
|
||||||
|
<div class="relative">
|
||||||
|
<ui-text-input v-model="markAsFinishedValue" type="number" label="" no-spinner custom-input-class="pr-5" @input="markAsFinishedChanged" />
|
||||||
|
<div class="absolute top-0 bottom-0 right-4 flex items-center">{{ markAsFinishedWhen === 'timeRemaining' ? '' : '%' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -99,7 +113,9 @@ export default {
|
|||||||
epubsAllowScriptedContent: false,
|
epubsAllowScriptedContent: false,
|
||||||
hideSingleBookSeries: false,
|
hideSingleBookSeries: false,
|
||||||
onlyShowLaterBooksInContinueSeries: false,
|
onlyShowLaterBooksInContinueSeries: false,
|
||||||
podcastSearchRegion: 'us'
|
podcastSearchRegion: 'us',
|
||||||
|
markAsFinishedWhen: 'timeRemaining',
|
||||||
|
markAsFinishedValue: 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -121,10 +137,34 @@ export default {
|
|||||||
providers() {
|
providers() {
|
||||||
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
|
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
|
||||||
return this.$store.state.scanners.providers
|
return this.$store.state.scanners.providers
|
||||||
|
},
|
||||||
|
maskAsFinishedWhenItems() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelSettingsLibraryMarkAsFinishedTimeRemaining,
|
||||||
|
value: 'timeRemaining'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelSettingsLibraryMarkAsFinishedPercentComplete,
|
||||||
|
value: 'percentComplete'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
markAsFinishedWhenChanged(val) {
|
||||||
|
if (val === 'percentComplete' && this.markAsFinishedValue > 100) {
|
||||||
|
this.markAsFinishedValue = 100
|
||||||
|
}
|
||||||
|
this.formUpdated()
|
||||||
|
},
|
||||||
|
markAsFinishedChanged(val) {
|
||||||
|
this.formUpdated()
|
||||||
|
},
|
||||||
getLibraryData() {
|
getLibraryData() {
|
||||||
|
let markAsFinishedTimeRemaining = this.markAsFinishedWhen === 'timeRemaining' ? Number(this.markAsFinishedValue) : null
|
||||||
|
let markAsFinishedPercentComplete = this.markAsFinishedWhen === 'percentComplete' ? Number(this.markAsFinishedValue) : null
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings: {
|
settings: {
|
||||||
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
|
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
|
||||||
@ -135,7 +175,9 @@ export default {
|
|||||||
epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
|
epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
|
||||||
hideSingleBookSeries: !!this.hideSingleBookSeries,
|
hideSingleBookSeries: !!this.hideSingleBookSeries,
|
||||||
onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries,
|
onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries,
|
||||||
podcastSearchRegion: this.podcastSearchRegion
|
podcastSearchRegion: this.podcastSearchRegion,
|
||||||
|
markAsFinishedTimeRemaining: markAsFinishedTimeRemaining,
|
||||||
|
markAsFinishedPercentComplete: markAsFinishedPercentComplete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -152,6 +194,11 @@ export default {
|
|||||||
this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries
|
this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries
|
||||||
this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
|
this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
|
||||||
this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us'
|
this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us'
|
||||||
|
this.markAsFinishedWhen = this.librarySettings.markAsFinishedTimeRemaining ? 'timeRemaining' : 'percentComplete'
|
||||||
|
if (!this.librarySettings.markAsFinishedTimeRemaining && !this.librarySettings.markAsFinishedPercentComplete) {
|
||||||
|
this.markAsFinishedWhen = 'timeRemaining'
|
||||||
|
}
|
||||||
|
this.markAsFinishedValue = this.librarySettings.markAsFinishedTimeRemaining || this.librarySettings.markAsFinishedPercentComplete || 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -562,6 +562,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
|
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
|
||||||
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
|
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Percent complete is greater than",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Time remaining is less than (seconds)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Mark media item as finished when",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Skip earlier books in Continue Series",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Skip earlier books in Continue Series",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "The Continue Series home page shelf shows the first book not started in series that have at least one book finished and no books in progress. Enabling this setting will continue series from the furthest completed book instead of the first book not started.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "The Continue Series home page shelf shows the first book not started in series that have at least one book finished and no books in progress. Enabling this setting will continue series from the furthest completed book instead of the first book not started.",
|
||||||
"LabelSettingsParseSubtitles": "Parse subtitles",
|
"LabelSettingsParseSubtitles": "Parse subtitles",
|
||||||
|
@ -255,15 +255,18 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate settings
|
// Validate settings
|
||||||
|
const defaultLibrarySettings = Database.libraryModel.getDefaultLibrarySettingsForMediaType(req.library.mediaType)
|
||||||
const updatedSettings = {
|
const updatedSettings = {
|
||||||
...(req.library.settings || Database.libraryModel.getDefaultLibrarySettingsForMediaType(req.library.mediaType))
|
...(req.library.settings || defaultLibrarySettings)
|
||||||
}
|
}
|
||||||
let hasUpdates = false
|
let hasUpdates = false
|
||||||
let hasUpdatedDisableWatcher = false
|
let hasUpdatedDisableWatcher = false
|
||||||
let hasUpdatedScanCron = false
|
let hasUpdatedScanCron = false
|
||||||
if (req.body.settings) {
|
if (req.body.settings) {
|
||||||
for (const key in req.body.settings) {
|
for (const key in req.body.settings) {
|
||||||
if (updatedSettings[key] === undefined) continue
|
if (!Object.keys(defaultLibrarySettings).includes(key)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (key === 'metadataPrecedence') {
|
if (key === 'metadataPrecedence') {
|
||||||
if (!Array.isArray(req.body.settings[key])) {
|
if (!Array.isArray(req.body.settings[key])) {
|
||||||
@ -285,6 +288,28 @@ class LibraryController {
|
|||||||
updatedSettings[key] = req.body.settings[key]
|
updatedSettings[key] = req.body.settings[key]
|
||||||
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
||||||
}
|
}
|
||||||
|
} else if (key === 'markAsFinishedPercentComplete') {
|
||||||
|
if (req.body.settings[key] !== null && isNaN(req.body.settings[key])) {
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be a number`)
|
||||||
|
} else if (req.body.settings[key] !== null && (Number(req.body.settings[key]) < 0 || Number(req.body.settings[key]) > 100)) {
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be between 0 and 100`)
|
||||||
|
}
|
||||||
|
if (req.body.settings[key] !== updatedSettings[key]) {
|
||||||
|
hasUpdates = true
|
||||||
|
updatedSettings[key] = Number(req.body.settings[key])
|
||||||
|
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
||||||
|
}
|
||||||
|
} else if (key === 'markAsFinishedTimeRemaining') {
|
||||||
|
if (req.body.settings[key] !== null && isNaN(req.body.settings[key])) {
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be a number`)
|
||||||
|
} else if (req.body.settings[key] !== null && Number(req.body.settings[key]) < 0) {
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be greater than or equal to 0`)
|
||||||
|
}
|
||||||
|
if (req.body.settings[key] !== updatedSettings[key]) {
|
||||||
|
hasUpdates = true
|
||||||
|
updatedSettings[key] = Number(req.body.settings[key])
|
||||||
|
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof req.body.settings[key] !== typeof updatedSettings[key]) {
|
if (typeof req.body.settings[key] !== typeof updatedSettings[key]) {
|
||||||
return res.status(400).send(`Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
|
return res.status(400).send(`Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
|
||||||
|
@ -349,7 +349,7 @@ class PlaybackSessionManager {
|
|||||||
progress: session.progress
|
progress: session.progress
|
||||||
// TODO: Add support for passing in these values from library settings
|
// TODO: Add support for passing in these values from library settings
|
||||||
// markAsFinishedTimeRemaining: 5,
|
// markAsFinishedTimeRemaining: 5,
|
||||||
// markAsFinishedPercentageComplete: 95
|
// markAsFinishedPercentComplete: 95
|
||||||
})
|
})
|
||||||
if (updateResponse.mediaProgress) {
|
if (updateResponse.mediaProgress) {
|
||||||
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
|
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
|
||||||
|
@ -12,6 +12,8 @@ const Logger = require('../Logger')
|
|||||||
* @property {boolean} hideSingleBookSeries Do not show series that only have 1 book
|
* @property {boolean} hideSingleBookSeries Do not show series that only have 1 book
|
||||||
* @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read
|
* @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read
|
||||||
* @property {string[]} metadataPrecedence
|
* @property {string[]} metadataPrecedence
|
||||||
|
* @property {number} markAsFinishedTimeRemaining Time remaining in seconds to mark as finished. (defaults to 10s)
|
||||||
|
* @property {number} markAsFinishedPercentComplete Percent complete to mark as finished (0-100). If this is set it will be used over markAsFinishedTimeRemaining.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Library extends Model {
|
class Library extends Model {
|
||||||
@ -57,7 +59,9 @@ class Library extends Model {
|
|||||||
coverAspectRatio: 1, // Square
|
coverAspectRatio: 1, // Square
|
||||||
disableWatcher: false,
|
disableWatcher: false,
|
||||||
autoScanCronExpression: null,
|
autoScanCronExpression: null,
|
||||||
podcastSearchRegion: 'us'
|
podcastSearchRegion: 'us',
|
||||||
|
markAsFinishedPercentComplete: null,
|
||||||
|
markAsFinishedTimeRemaining: 10
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@ -70,7 +74,9 @@ class Library extends Model {
|
|||||||
epubsAllowScriptedContent: false,
|
epubsAllowScriptedContent: false,
|
||||||
hideSingleBookSeries: false,
|
hideSingleBookSeries: false,
|
||||||
onlyShowLaterBooksInContinueSeries: false,
|
onlyShowLaterBooksInContinueSeries: false,
|
||||||
metadataPrecedence: this.defaultMetadataPrecedence
|
metadataPrecedence: this.defaultMetadataPrecedence,
|
||||||
|
markAsFinishedPercentComplete: null,
|
||||||
|
markAsFinishedTimeRemaining: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,18 +229,18 @@ class MediaProgress extends Model {
|
|||||||
const timeRemaining = this.duration - this.currentTime
|
const timeRemaining = this.duration - this.currentTime
|
||||||
|
|
||||||
// Check if progress is far enough to mark as finished
|
// Check if progress is far enough to mark as finished
|
||||||
// - If markAsFinishedPercentageComplete is provided, use that otherwise use markAsFinishedTimeRemaining (default 5 seconds)
|
// - If markAsFinishedPercentComplete is provided, use that otherwise use markAsFinishedTimeRemaining (default 10 seconds)
|
||||||
let shouldMarkAsFinished = false
|
let shouldMarkAsFinished = false
|
||||||
if (!this.isFinished && this.duration) {
|
if (!this.isFinished && this.duration) {
|
||||||
if (!isNullOrNaN(progressPayload.markAsFinishedPercentageComplete)) {
|
if (!isNullOrNaN(progressPayload.markAsFinishedPercentComplete)) {
|
||||||
const markAsFinishedPercentageComplete = Number(progressPayload.markAsFinishedPercentageComplete) / 100
|
const markAsFinishedPercentComplete = Number(progressPayload.markAsFinishedPercentComplete) / 100
|
||||||
shouldMarkAsFinished = markAsFinishedPercentageComplete <= this.progress
|
shouldMarkAsFinished = markAsFinishedPercentComplete < this.progress
|
||||||
if (shouldMarkAsFinished) {
|
if (shouldMarkAsFinished) {
|
||||||
Logger.debug(`[MediaProgress] Marking media progress as finished because progress (${this.progress}) is greater than ${markAsFinishedPercentageComplete}`)
|
Logger.debug(`[MediaProgress] Marking media progress as finished because progress (${this.progress}) is greater than ${markAsFinishedPercentComplete}`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const markAsFinishedTimeRemaining = isNullOrNaN(progressPayload.markAsFinishedTimeRemaining) ? 5 : Number(progressPayload.markAsFinishedTimeRemaining)
|
const markAsFinishedTimeRemaining = isNullOrNaN(progressPayload.markAsFinishedTimeRemaining) ? 10 : Number(progressPayload.markAsFinishedTimeRemaining)
|
||||||
shouldMarkAsFinished = timeRemaining <= markAsFinishedTimeRemaining
|
shouldMarkAsFinished = timeRemaining < markAsFinishedTimeRemaining
|
||||||
if (shouldMarkAsFinished) {
|
if (shouldMarkAsFinished) {
|
||||||
Logger.debug(`[MediaProgress] Marking media progress as finished because time remaining (${timeRemaining}) is less than ${markAsFinishedTimeRemaining} seconds`)
|
Logger.debug(`[MediaProgress] Marking media progress as finished because time remaining (${timeRemaining}) is less than ${markAsFinishedTimeRemaining} seconds`)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ const { DataTypes, Model } = sequelize
|
|||||||
* @property {string} [finishedAt]
|
* @property {string} [finishedAt]
|
||||||
* @property {number} [lastUpdate]
|
* @property {number} [lastUpdate]
|
||||||
* @property {number} [markAsFinishedTimeRemaining]
|
* @property {number} [markAsFinishedTimeRemaining]
|
||||||
* @property {number} [markAsFinishedPercentageComplete]
|
* @property {number} [markAsFinishedPercentComplete]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class User extends Model {
|
class User extends Model {
|
||||||
|
Loading…
Reference in New Issue
Block a user