mirror of
https://github.com/gotson/komga.git
synced 2025-01-09 04:08:00 +08:00
feat: library deep scan is now a parameter of the scan API
Closes: #1137
This commit is contained in:
parent
308a068f42
commit
63e3e7a8ac
@ -108,13 +108,6 @@
|
||||
</v-tooltip>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
|
||||
<v-checkbox
|
||||
v-model="form.scanDeep"
|
||||
:label="$t('dialog.edit_library.field_scanner_deep_scan')"
|
||||
hide-details
|
||||
class="mx-4"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
@ -392,7 +385,6 @@ export default Vue.extend({
|
||||
importLocalArtwork: true,
|
||||
importBarcodeIsbn: false,
|
||||
scanForceModifiedTime: false,
|
||||
scanDeep: false,
|
||||
repairExtensions: false,
|
||||
convertToCbz: false,
|
||||
emptyTrashAfterScan: false,
|
||||
@ -525,7 +517,6 @@ export default Vue.extend({
|
||||
this.form.importLocalArtwork = library ? library.importLocalArtwork : true
|
||||
this.form.importBarcodeIsbn = library ? library.importBarcodeIsbn : false
|
||||
this.form.scanForceModifiedTime = library ? library.scanForceModifiedTime : false
|
||||
this.form.scanDeep = library ? library.scanDeep : false
|
||||
this.form.repairExtensions = library ? library.repairExtensions : false
|
||||
this.form.convertToCbz = library ? library.convertToCbz : false
|
||||
this.form.emptyTrashAfterScan = library ? library.emptyTrashAfterScan : false
|
||||
@ -553,7 +544,6 @@ export default Vue.extend({
|
||||
importLocalArtwork: this.form.importLocalArtwork,
|
||||
importBarcodeIsbn: this.form.importBarcodeIsbn,
|
||||
scanForceModifiedTime: this.form.scanForceModifiedTime,
|
||||
scanDeep: this.form.scanDeep,
|
||||
repairExtensions: this.form.repairExtensions,
|
||||
convertToCbz: this.form.convertToCbz,
|
||||
emptyTrashAfterScan: this.form.emptyTrashAfterScan,
|
||||
|
@ -22,7 +22,7 @@
|
||||
<v-list-item @click="markUnread" v-if="!isUnread">
|
||||
<v-list-item-title>{{ $t('menu.mark_unread') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="promptDeleteBook" class="list-warning" v-if="isAdmin">
|
||||
<v-list-item @click="promptDeleteBook" class="list-danger" v-if="isAdmin">
|
||||
<v-list-item-title>{{ $t('menu.delete') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
@ -8,7 +8,7 @@
|
||||
</template>
|
||||
<v-list dense>
|
||||
<v-list-item @click="promptDeleteCollection"
|
||||
class="list-warning">
|
||||
class="list-danger">
|
||||
<v-list-item-title>{{ $t('menu.delete') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
@ -10,6 +10,9 @@
|
||||
<v-list-item @click="scan">
|
||||
<v-list-item-title>{{ $t('menu.scan_library_files') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="scan(true)" class="list-warning">
|
||||
<v-list-item-title>{{ $t('menu.scan_library_files_deep') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="confirmAnalyzeModal = true">
|
||||
<v-list-item-title>{{ $t('menu.analyze') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
@ -23,7 +26,7 @@
|
||||
<v-list-item-title>{{ $t('menu.edit') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="promptDeleteLibrary"
|
||||
class="list-warning">
|
||||
class="list-danger">
|
||||
<v-list-item-title>{{ $t('menu.delete') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
@ -81,8 +84,8 @@ export default Vue.extend({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
scan() {
|
||||
this.$komgaLibraries.scanLibrary(this.library)
|
||||
scan(scanDeep: boolean = false) {
|
||||
this.$komgaLibraries.scanLibrary(this.library, scanDeep)
|
||||
},
|
||||
analyze() {
|
||||
this.$komgaLibraries.analyzeLibrary(this.library)
|
||||
|
@ -8,7 +8,7 @@
|
||||
</template>
|
||||
<v-list dense>
|
||||
<v-list-item @click="promptDeleteReadList"
|
||||
class="list-warning">
|
||||
class="list-danger">
|
||||
<v-list-item-title>{{ $t('menu.delete') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<v-list-item @click="markUnread" v-if="!isUnread">
|
||||
<v-list-item-title>{{ $t('menu.mark_unread') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="promptDeleteSeries" class="list-warning" v-if="isAdmin">
|
||||
<v-list-item @click="promptDeleteSeries" class="list-danger" v-if="isAdmin">
|
||||
<v-list-item-title>{{ $t('menu.delete') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
@ -425,7 +425,6 @@
|
||||
"field_name": "Name",
|
||||
"field_repair_extensions": "Automatically repair incorrect file extensions",
|
||||
"field_root_folder": "Root folder",
|
||||
"field_scanner_deep_scan": "Deep scan",
|
||||
"field_scanner_empty_trash_after_scan": "Empty trash automatically after every scan",
|
||||
"field_scanner_force_directory_modified_time": "Force directory modified time",
|
||||
"field_series_cover": "Series cover",
|
||||
@ -590,9 +589,9 @@
|
||||
"count": "Count",
|
||||
"delete_count": "Deletion count",
|
||||
"delete_size": "Space saved",
|
||||
"match_count": "Match count",
|
||||
"size": "Size",
|
||||
"total_size": "Total size",
|
||||
"match_count": "Match count"
|
||||
"total_size": "Total size"
|
||||
},
|
||||
"info": "Deleting duplicate pages will modify your files. Backup your files and use manual deletion before using automatic deletion.",
|
||||
"known": "Known",
|
||||
@ -752,6 +751,7 @@
|
||||
"mark_unread": "Mark as unread",
|
||||
"refresh_metadata": "Refresh metadata",
|
||||
"scan_library_files": "Scan library files",
|
||||
"scan_library_files_deep": "Scan library files (deep)",
|
||||
"select_all": "Select all"
|
||||
},
|
||||
"metrics": {
|
||||
@ -803,6 +803,7 @@
|
||||
"button_cancel_all_tasks": "Cancel all tasks",
|
||||
"button_empty_trash": "Empty trash for all libraries",
|
||||
"button_scan_libraries": "Scan all libraries",
|
||||
"button_scan_libraries_deep": "Scan all libraries (deep)",
|
||||
"button_shutdown": "Shut down",
|
||||
"notification_tasks_cancelled": "No tasks to cancel | One task cancelled | {count} tasks cancelled",
|
||||
"section_title": "Server Management"
|
||||
|
@ -6,11 +6,11 @@ const API_LIBRARIES = '/api/v1/libraries'
|
||||
export default class KomgaLibrariesService {
|
||||
private http: AxiosInstance
|
||||
|
||||
constructor (http: AxiosInstance) {
|
||||
constructor(http: AxiosInstance) {
|
||||
this.http = http
|
||||
}
|
||||
|
||||
async getLibraries (): Promise<LibraryDto[]> {
|
||||
async getLibraries(): Promise<LibraryDto[]> {
|
||||
try {
|
||||
return (await this.http.get(API_LIBRARIES)).data
|
||||
} catch (e) {
|
||||
@ -22,7 +22,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async getLibrary (libraryId: string): Promise<LibraryDto> {
|
||||
async getLibrary(libraryId: string): Promise<LibraryDto> {
|
||||
try {
|
||||
return (await this.http.get(`${API_LIBRARIES}/${libraryId}`)).data
|
||||
} catch (e) {
|
||||
@ -34,7 +34,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async postLibrary (library: LibraryCreationDto): Promise<LibraryDto> {
|
||||
async postLibrary(library: LibraryCreationDto): Promise<LibraryDto> {
|
||||
try {
|
||||
return (await this.http.post(API_LIBRARIES, library)).data
|
||||
} catch (e) {
|
||||
@ -46,7 +46,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateLibrary (libraryId: string, library: LibraryUpdateDto) {
|
||||
async updateLibrary(libraryId: string, library: LibraryUpdateDto) {
|
||||
try {
|
||||
await this.http.put(`${API_LIBRARIES}/${libraryId}`, library)
|
||||
} catch (e) {
|
||||
@ -58,7 +58,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteLibrary (library: LibraryDto) {
|
||||
async deleteLibrary(library: LibraryDto) {
|
||||
try {
|
||||
await this.http.delete(`${API_LIBRARIES}/${library.id}`)
|
||||
} catch (e) {
|
||||
@ -70,9 +70,11 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async scanLibrary (library: LibraryDto) {
|
||||
async scanLibrary(library: LibraryDto, scanDeep: boolean = false) {
|
||||
try {
|
||||
await this.http.post(`${API_LIBRARIES}/${library.id}/scan`)
|
||||
await this.http.post(`${API_LIBRARIES}/${library.id}/scan`, null, {
|
||||
params: {deep: scanDeep},
|
||||
})
|
||||
} catch (e) {
|
||||
let msg = `An error occurred while trying to scan library '${library.name}'`
|
||||
if (e.response.data.message) {
|
||||
@ -82,7 +84,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async analyzeLibrary (library: LibraryDto) {
|
||||
async analyzeLibrary(library: LibraryDto) {
|
||||
try {
|
||||
await this.http.post(`${API_LIBRARIES}/${library.id}/analyze`)
|
||||
} catch (e) {
|
||||
@ -94,7 +96,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async refreshMetadata (library: LibraryDto) {
|
||||
async refreshMetadata(library: LibraryDto) {
|
||||
try {
|
||||
await this.http.post(`${API_LIBRARIES}/${library.id}/metadata/refresh`)
|
||||
} catch (e) {
|
||||
@ -106,7 +108,7 @@ export default class KomgaLibrariesService {
|
||||
}
|
||||
}
|
||||
|
||||
async emptyTrash (library: LibraryDto) {
|
||||
async emptyTrash(library: LibraryDto) {
|
||||
try {
|
||||
await this.http.post(`${API_LIBRARIES}/${library.id}/empty-trash`)
|
||||
} catch (e) {
|
||||
|
@ -1,5 +1,13 @@
|
||||
.list-danger:hover {
|
||||
background: #ff5252;
|
||||
}
|
||||
|
||||
.list-danger:hover .v-list-item__title {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.list-warning:hover {
|
||||
background: #F44336;
|
||||
background: #fb8c00;
|
||||
}
|
||||
|
||||
.list-warning:hover .v-list-item__title {
|
||||
|
@ -14,7 +14,6 @@ export interface LibraryCreationDto {
|
||||
importLocalArtwork: boolean,
|
||||
importBarcodeIsbn: boolean,
|
||||
scanForceModifiedTime: boolean,
|
||||
scanDeep: boolean,
|
||||
repairExtensions: boolean,
|
||||
convertToCbz: boolean,
|
||||
emptyTrashAfterScan: boolean,
|
||||
@ -38,7 +37,6 @@ export interface LibraryUpdateDto {
|
||||
importLocalArtwork: boolean,
|
||||
importBarcodeIsbn: boolean,
|
||||
scanForceModifiedTime: boolean,
|
||||
scanDeep: boolean,
|
||||
repairExtensions: boolean,
|
||||
convertToCbz: boolean,
|
||||
emptyTrashAfterScan: boolean,
|
||||
@ -63,7 +61,6 @@ export interface LibraryDto {
|
||||
importLocalArtwork: boolean,
|
||||
importBarcodeIsbn: boolean,
|
||||
scanForceModifiedTime: boolean,
|
||||
scanDeep: boolean,
|
||||
repairExtensions: boolean,
|
||||
convertToCbz: boolean,
|
||||
emptyTrashAfterScan: boolean,
|
||||
|
@ -7,6 +7,12 @@
|
||||
<v-col cols="auto">
|
||||
<v-btn @click="scanAllLibraries">{{ $t('server.server_management.button_scan_libraries') }}</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="auto">
|
||||
<v-btn @click="scanAllLibraries(true)"
|
||||
color="warning"
|
||||
>{{ $t('server.server_management.button_scan_libraries_deep') }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="auto">
|
||||
<v-btn @click="confirmEmptyTrash = true">{{ $t('server.server_management.button_empty_trash') }}</v-btn>
|
||||
</v-col>
|
||||
@ -68,9 +74,9 @@ export default Vue.extend({
|
||||
this.$komgaLibraries.emptyTrash(library)
|
||||
})
|
||||
},
|
||||
scanAllLibraries() {
|
||||
scanAllLibraries(scanDeep: boolean = false) {
|
||||
this.libraries.forEach(library => {
|
||||
this.$komgaLibraries.scanLibrary(library)
|
||||
this.$komgaLibraries.scanLibrary(library, scanDeep)
|
||||
})
|
||||
},
|
||||
async cancelAllTasks() {
|
||||
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE LIBRARY
|
||||
RENAME COLUMN SCAN_DEEP to _UNUSED;
|
@ -16,9 +16,9 @@ sealed class Task(priority: Int = DEFAULT_PRIORITY, val groupId: String? = null)
|
||||
abstract fun uniqueId(): String
|
||||
val priority = priority.coerceIn(0, 9)
|
||||
|
||||
class ScanLibrary(val libraryId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) {
|
||||
override fun uniqueId() = "SCAN_LIBRARY_$libraryId"
|
||||
override fun toString(): String = "ScanLibrary(libraryId='$libraryId', priority='$priority')"
|
||||
class ScanLibrary(val libraryId: String, val scanDeep: Boolean, priority: Int = DEFAULT_PRIORITY) : Task(priority) {
|
||||
override fun uniqueId() = "SCAN_LIBRARY_${libraryId}_DEEP_$scanDeep"
|
||||
override fun toString(): String = "ScanLibrary(libraryId='$libraryId', scanDeep='$scanDeep', priority='$priority')"
|
||||
}
|
||||
|
||||
class FindBooksToConvert(val libraryId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) {
|
||||
|
@ -42,8 +42,8 @@ class TaskEmitter(
|
||||
libraryRepository.findAll().forEach { scanLibrary(it.id) }
|
||||
}
|
||||
|
||||
fun scanLibrary(libraryId: String, priority: Int = DEFAULT_PRIORITY) {
|
||||
submitTask(Task.ScanLibrary(libraryId, priority))
|
||||
fun scanLibrary(libraryId: String, scanDeep: Boolean = false, priority: Int = DEFAULT_PRIORITY) {
|
||||
submitTask(Task.ScanLibrary(libraryId, scanDeep, priority))
|
||||
}
|
||||
|
||||
fun emptyTrash(libraryId: String, priority: Int = DEFAULT_PRIORITY) {
|
||||
|
@ -57,7 +57,7 @@ class TaskHandler(
|
||||
when (task) {
|
||||
is Task.ScanLibrary ->
|
||||
libraryRepository.findByIdOrNull(task.libraryId)?.let { library ->
|
||||
libraryContentLifecycle.scanRootFolder(library)
|
||||
libraryContentLifecycle.scanRootFolder(library, task.scanDeep)
|
||||
taskEmitter.analyzeUnknownAndOutdatedBooks(library)
|
||||
taskEmitter.repairExtensions(library, LOW_PRIORITY)
|
||||
taskEmitter.findBooksToConvert(library, LOWEST_PRIORITY)
|
||||
|
@ -21,7 +21,6 @@ data class Library(
|
||||
val importLocalArtwork: Boolean = true,
|
||||
val importBarcodeIsbn: Boolean = true,
|
||||
val scanForceModifiedTime: Boolean = false,
|
||||
val scanDeep: Boolean = false,
|
||||
val repairExtensions: Boolean = false,
|
||||
val convertToCbz: Boolean = false,
|
||||
val emptyTrashAfterScan: Boolean = false,
|
||||
|
@ -62,7 +62,7 @@ class LibraryContentLifecycle(
|
||||
private val eventPublisher: EventPublisher,
|
||||
) {
|
||||
|
||||
fun scanRootFolder(library: Library) {
|
||||
fun scanRootFolder(library: Library, scanDeep: Boolean = false) {
|
||||
logger.info { "Updating library: $library" }
|
||||
measureTime {
|
||||
val scanResult = try {
|
||||
@ -136,7 +136,7 @@ class LibraryContentLifecycle(
|
||||
logger.info { "Series changed on disk, updating: $existingSeries" }
|
||||
seriesRepository.update(existingSeries.copy(fileLastModified = newSeries.fileLastModified, deletedDate = null))
|
||||
}
|
||||
if (library.scanDeep || seriesChanged) {
|
||||
if (scanDeep || seriesChanged) {
|
||||
// update list of books with existing entities if they exist
|
||||
val existingBooks = bookRepository.findAllBySeriesId(existingSeries.id)
|
||||
logger.debug { "Existing books: $existingBooks" }
|
||||
|
@ -72,7 +72,6 @@ class LibraryDao(
|
||||
.set(l.IMPORT_LOCAL_ARTWORK, library.importLocalArtwork)
|
||||
.set(l.IMPORT_BARCODE_ISBN, library.importBarcodeIsbn)
|
||||
.set(l.SCAN_FORCE_MODIFIED_TIME, library.scanForceModifiedTime)
|
||||
.set(l.SCAN_DEEP, library.scanDeep)
|
||||
.set(l.REPAIR_EXTENSIONS, library.repairExtensions)
|
||||
.set(l.CONVERT_TO_CBZ, library.convertToCbz)
|
||||
.set(l.EMPTY_TRASH_AFTER_SCAN, library.emptyTrashAfterScan)
|
||||
@ -100,7 +99,6 @@ class LibraryDao(
|
||||
.set(l.IMPORT_LOCAL_ARTWORK, library.importLocalArtwork)
|
||||
.set(l.IMPORT_BARCODE_ISBN, library.importBarcodeIsbn)
|
||||
.set(l.SCAN_FORCE_MODIFIED_TIME, library.scanForceModifiedTime)
|
||||
.set(l.SCAN_DEEP, library.scanDeep)
|
||||
.set(l.REPAIR_EXTENSIONS, library.repairExtensions)
|
||||
.set(l.CONVERT_TO_CBZ, library.convertToCbz)
|
||||
.set(l.EMPTY_TRASH_AFTER_SCAN, library.emptyTrashAfterScan)
|
||||
@ -131,7 +129,6 @@ class LibraryDao(
|
||||
importLocalArtwork = importLocalArtwork,
|
||||
importBarcodeIsbn = importBarcodeIsbn,
|
||||
scanForceModifiedTime = scanForceModifiedTime,
|
||||
scanDeep = scanDeep,
|
||||
repairExtensions = repairExtensions,
|
||||
convertToCbz = convertToCbz,
|
||||
emptyTrashAfterScan = emptyTrashAfterScan,
|
||||
|
@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.PutMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.server.ResponseStatusException
|
||||
@ -90,7 +91,6 @@ class LibraryController(
|
||||
importLocalArtwork = library.importLocalArtwork,
|
||||
importBarcodeIsbn = library.importBarcodeIsbn,
|
||||
scanForceModifiedTime = library.scanForceModifiedTime,
|
||||
scanDeep = library.scanDeep,
|
||||
repairExtensions = library.repairExtensions,
|
||||
convertToCbz = library.convertToCbz,
|
||||
emptyTrashAfterScan = library.emptyTrashAfterScan,
|
||||
@ -136,7 +136,6 @@ class LibraryController(
|
||||
importLocalArtwork = library.importLocalArtwork,
|
||||
importBarcodeIsbn = library.importBarcodeIsbn,
|
||||
scanForceModifiedTime = library.scanForceModifiedTime,
|
||||
scanDeep = library.scanDeep,
|
||||
repairExtensions = library.repairExtensions,
|
||||
convertToCbz = library.convertToCbz,
|
||||
emptyTrashAfterScan = library.emptyTrashAfterScan,
|
||||
@ -173,9 +172,12 @@ class LibraryController(
|
||||
@PostMapping("{libraryId}/scan")
|
||||
@PreAuthorize("hasRole('$ROLE_ADMIN')")
|
||||
@ResponseStatus(HttpStatus.ACCEPTED)
|
||||
fun scan(@PathVariable libraryId: String) {
|
||||
fun scan(
|
||||
@PathVariable libraryId: String,
|
||||
@RequestParam(required = false) deep: Boolean = false,
|
||||
) {
|
||||
libraryRepository.findByIdOrNull(libraryId)?.let { library ->
|
||||
taskEmitter.scanLibrary(library.id, HIGHEST_PRIORITY)
|
||||
taskEmitter.scanLibrary(library.id, deep, HIGHEST_PRIORITY)
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@ data class LibraryCreationDto(
|
||||
val importLocalArtwork: Boolean = true,
|
||||
val importBarcodeIsbn: Boolean = true,
|
||||
val scanForceModifiedTime: Boolean = false,
|
||||
val scanDeep: Boolean = false,
|
||||
val repairExtensions: Boolean = false,
|
||||
val convertToCbz: Boolean = false,
|
||||
val emptyTrashAfterScan: Boolean = false,
|
||||
|
@ -18,7 +18,6 @@ data class LibraryDto(
|
||||
val importLocalArtwork: Boolean,
|
||||
val importBarcodeIsbn: Boolean,
|
||||
val scanForceModifiedTime: Boolean,
|
||||
val scanDeep: Boolean,
|
||||
val repairExtensions: Boolean,
|
||||
val convertToCbz: Boolean,
|
||||
val emptyTrashAfterScan: Boolean,
|
||||
@ -44,7 +43,6 @@ fun Library.toDto(includeRoot: Boolean) = LibraryDto(
|
||||
importLocalArtwork = importLocalArtwork,
|
||||
importBarcodeIsbn = importBarcodeIsbn,
|
||||
scanForceModifiedTime = scanForceModifiedTime,
|
||||
scanDeep = scanDeep,
|
||||
repairExtensions = repairExtensions,
|
||||
convertToCbz = convertToCbz,
|
||||
emptyTrashAfterScan = emptyTrashAfterScan,
|
||||
|
@ -16,7 +16,6 @@ data class LibraryUpdateDto(
|
||||
val importLocalArtwork: Boolean,
|
||||
val importBarcodeIsbn: Boolean,
|
||||
val scanForceModifiedTime: Boolean,
|
||||
val scanDeep: Boolean,
|
||||
val repairExtensions: Boolean,
|
||||
val convertToCbz: Boolean,
|
||||
val emptyTrashAfterScan: Boolean,
|
||||
|
Loading…
Reference in New Issue
Block a user