diff --git a/app/main.py b/app/main.py index 94935dc..d733672 100644 --- a/app/main.py +++ b/app/main.py @@ -490,55 +490,6 @@ def settings(): return render_template('settings.html') -@main.route('/trigger-thumbnail-generation', methods=['POST']) -def trigger_thumbnail_generation(): - try: - with open('/import/thumbnail.flag', 'w') as f: - f.write("trigger") - flash("Thumbnail regeneration has been triggered.", "success") - except Exception as e: - flash(f"Failed to trigger thumbnail regeneration: {e}", "danger") - - return redirect(url_for('main.settings')) - - -@main.route('/import-images') -def trigger_image_import(): - with open('/import/trigger.flag', 'w') as f: - f.write('start') - flash("Image import triggered.", "success") - return redirect(url_for('main.settings')) - - -@main.route('/reset-db', methods=['POST']) -def reset_db(): - """ - Safe reset that works with Postgres (TRUNCATE ... CASCADE). - Falls back to ordered deletes if TRUNCATE isn't supported (e.g., SQLite). - """ - try: - # Postgres fast path - db.session.execute(text(""" - TRUNCATE TABLE image_tags, archive_record, image_record, tag - RESTART IDENTITY CASCADE - """)) - db.session.commit() - except Exception: - # Fallback: manual delete order - db.session.execute(image_tags.delete()) - ArchiveRecord.query.delete() - ImageRecord.query.delete() - Tag.query.delete() - db.session.commit() - - # Optional: clear thumbs on disk to regenerate fresh - shutil.rmtree("/images/thumbs", ignore_errors=True) - os.makedirs("/images/thumbs", exist_ok=True) - - flash("Database has been reset. All records removed.", "info") - return redirect(url_for('main.settings')) - - # ---------------------------- # Tag add/remove endpoints # ---------------------------- @@ -870,28 +821,6 @@ def save_import_settings(): return jsonify(ok=False, error=str(e)), 500 -@main.get("/api/import-stats") -def get_import_stats(): - """Get import statistics including filtered image counts.""" - import json - stats_path = "/import/stats.json" - try: - if os.path.exists(stats_path): - with open(stats_path, "r") as f: - stats = json.load(f) - else: - stats = { - "total_processed": 0, - "total_imported": 0, - "filtered_by_dimension": 0, - "filtered_by_transparency": 0, - "filtered_by_duplicate": 0, - } - return jsonify(ok=True, stats=stats) - except Exception as e: - return jsonify(ok=False, error=str(e)), 500 - - # ---------------------------- # Image filter/cleanup endpoints # ---------------------------- diff --git a/app/static/style.css b/app/static/style.css index 9f7a1b1..bf7a952 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -953,37 +953,30 @@ header { ------------------------------------------------------------------------------*/ .settings-grid { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(2, 1fr); gap: 1.5rem; max-width: 1600px; margin: 1.5rem auto; padding: 0 1.5rem; align-items: start; } +.settings-grid-full { + max-width: 1600px; + margin: 1.5rem auto; + padding: 0 1.5rem; +} .settings-column { display: flex; flex-direction: column; gap: 1.5rem; } -@media (max-width: 1200px) { - .settings-grid { - grid-template-columns: repeat(2, 1fr); - } - .settings-column:first-child { - grid-column: 1 / -1; - flex-direction: row; - } - .settings-column:first-child > .settings-container { - flex: 1; - } -} @media (max-width: 768px) { .settings-grid { grid-template-columns: 1fr; padding: 0 1rem; } - .settings-column:first-child { - flex-direction: column; + .settings-grid-full { + padding: 0 1rem; } } .settings-container { diff --git a/app/tasks/import_file.py b/app/tasks/import_file.py index e43a596..26e5a74 100644 --- a/app/tasks/import_file.py +++ b/app/tasks/import_file.py @@ -273,8 +273,9 @@ def import_archive(self, task_id: int): Returns: dict with status and counts """ - from app.utils.image_importer import calculate_hash, compute_next_archive_tag_name - from pyunpack import Archive + from app.utils.image_importer import ( + calculate_hash, compute_next_archive_tag_name, extract_archive_resilient, ExtractError + ) task = ImportTask.query.get(task_id) if not task: @@ -305,13 +306,13 @@ def import_archive(self, task_id: int): # Get archive size archive_size = os.path.getsize(archive_path) - # Extract archive + # Extract archive using resilient extractor (tries unar then 7z for RAR) tmpdir = tempfile.mkdtemp(prefix='extract_') log.info(f"Extracting to: {tmpdir}") try: - Archive(archive_path).extractall(tmpdir) - except Exception as e: + extract_archive_resilient(archive_path, tmpdir) + except ExtractError as e: log.error(f"Extraction failed: {e}") if tmpdir and os.path.exists(tmpdir): shutil.rmtree(tmpdir, ignore_errors=True) diff --git a/app/templates/settings.html b/app/templates/settings.html index 1cf5164..2519509 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -4,38 +4,93 @@ {% block content %}
Use these tools to manage your image library. You can trigger imports, configure filters, and clean up unwanted images.
-Note: Resetting the database does not delete the actual image files from disk.
+ +Monitor and control the Celery-based import queue system.
+ ++ Workers: - | + Active Tasks: - +
+| File | +Type | +Status | +Error | +Time | +
|---|---|---|---|---|
| Loading... | ||||
Monitor and control the Celery-based import queue system.
- -- Workers: - | - Active Tasks: - -
-| File | -Type | -Status | -Error | -Time | -
|---|---|---|---|---|
| Loading... | ||||