**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

+12 -14
View File
@@ -1,11 +1,11 @@
from pathlib import Path
from django.contrib.auth import get_user_model
from django.contrib.auth.base_user import AbstractBaseUser
from django.conf import settings
from django.core.management.base import BaseCommand, CommandParser
from loguru import logger
from comic.models import Directory
from comic.processing import generate_directory
from comic.processing import reconcile
class Command(BaseCommand):
@@ -26,14 +26,12 @@ class Command(BaseCommand):
self.OUTPUT = options.get('out', False)
self.scan_directory()
def scan_directory(self, user: AbstractBaseUser | None = None, directory: Directory | None = None) -> None:
if not user:
user_model = get_user_model()
user = user_model.objects.first()
if not user:
logger.error("No user found, cannot scan comics.")
return
for item in generate_directory(user, directory):
if isinstance(item, Directory):
logger.info(item)
self.scan_directory(user, item)
def scan_directory(self, directory: Directory | None = None) -> None:
reconcile(directory)
path = Path(settings.COMIC_BOOK_VOLUME, directory.path) if directory else settings.COMIC_BOOK_VOLUME
if self.OUTPUT:
self.stdout.write(str(path))
else:
logger.info(path)
for child in Directory.objects.filter(parent=directory):
self.scan_directory(child)