**Refactor directory scanning and add scan task support**

- Added a new `scan_directory` task to enable folder scans as asynchronous tasks while maintaining compatibility with the immediate backend.
- Introduced the `reconcile` function, replacing `generate_directory` for improved separation of concerns between database writes and read operations.
- Established a unique constraint on `Directory` (`one_directory_name_per_parent`) to prevent duplicate directories under the same parent.
- Added a "Scan" button to the frontend for re-reading folders from disk, along with new task invocation endpoints in the API.
- Updated tests across modules to validate the new `scan_directory` task, unique constraints, and database indexing logic.
- Improved cleanup logic for stale files, directories, and thumbnails to handle concurrent operations efficiently.
- Simplified `scan_comics` management command by removing user dependency and aligning it with the new `reconcile` function.
- Enhanced frontend components (`TheComicReader`, `TheComicList`, and others) to include lifecycle method cleanups, prevent memory leaks, and handle task-based scans.
This commit is contained in:
ajurna committed 2026-10-13 15:58:06 +01:00
1 parent 4d0ba750ad
commit ce809ed1a9
18 files changed
+364 -81

No files matched your search

+17 -1
View File
@@ -11,6 +11,9 @@
<li><a class="dropdown-item" @click="markAll('mark_unread')"><font-awesome-icon icon='book' />Mark Un-read</a></li>
<li><a class="dropdown-item" @click="markAll('mark_read')"><font-awesome-icon icon='book-open' />Mark read</a></li>
</ul>
<button type="button" class="btn btn-outline-secondary" :disabled="scanning" title="Read this folder from disk again" @click="scanFolder">
<font-awesome-icon icon='refresh' />{{ scanning ? 'Scanning…' : 'Scan' }}
</button>
</div>
</div>
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-6 row-cols-xl-auto mt-1" >
@@ -49,7 +52,8 @@ export default {
filter_read: false,
filter_unread: false
},
loading: true
loading: true,
scanning: false
}},
props: {
selector: String
@@ -68,6 +72,18 @@ export default {
})
.catch((error) => {console.log(error)})
},
scanFolder () {
this.scanning = true
api.post('/api/browse/scan/', { selector: this.selector || null })
.then(response => {
this.comics = response.data
this.scanning = false
})
.catch((error) => {
console.log(error)
this.scanning = false
})
},
markPreviousRead (selector) {
let selectors = []
this.comics.every((item) => {