diff --git a/search_db_analyzer.py b/search_db_analyzer.py index 6d87e3f..a2fbd40 100644 --- a/search_db_analyzer.py +++ b/search_db_analyzer.py @@ -10,6 +10,32 @@ APP_CONFIG = auth.return_app_config() BASE_DIR = os.path.dirname(os.path.abspath(__file__)) SEARCH_DB_PATH = os.path.join(BASE_DIR, "search.db") +# Filetype buckets (extension-based, lowercase, leading dot). +FILETYPE_BUCKETS = [ + ("Liedtexte", { + ".sng" + }), + ("Image", { + ".png", ".gif", ".bmp", ".webp", ".tiff", ".tif", ".svg", ".ico" + }), + ("Video", { + ".mp4", ".m4v", ".mov", ".avi", ".mkv", ".webm", ".mpg", ".mpeg", ".3gp", ".3g2", ".wmv" + }), + ("Photo", { + ".jpg", ".jpeg", ".heic", ".heif", ".dng", ".cr2", ".cr3", ".arw", ".nef", ".orf", ".rw2", ".raf" + }), + ("Document", { + ".pdf", ".doc", ".docx", ".ppt", ".pptx", ".txt", ".rtf", ".md", ".odt", ".pages", ".key", ".note" + }), + ("Table", { + ".xls", ".xlsx", ".csv", ".ods", ".tsv" + }), + ("Audio", { + ".mp3", ".wav", ".m4a", ".flac", ".ogg", ".aac", ".wma", ".aiff", ".alac" + }), +] +FILETYPE_ORDER = [label for label, _ in FILETYPE_BUCKETS] + ["Misc"] + # Open search.db in read-only mode to avoid accidental writes. search_db = sqlite3.connect(f"file:{SEARCH_DB_PATH}?mode=ro", uri=True, check_same_thread=False) search_db.row_factory = sqlite3.Row @@ -20,6 +46,32 @@ def _normalize_folder_path(folder_path: str) -> str: return folder_path.replace("\\", "/").strip().strip("/") +def _bucket_for_filetype(filetype: str) -> str: + if not filetype: + return "Misc" + ft = str(filetype).strip().lower() + if not ft: + return "Misc" + + if "/" in ft and not ft.startswith("."): + if ft.startswith("image/"): + return "Image" + if ft.startswith("video/"): + return "Video" + if ft.startswith("audio/"): + return "Audio" + if ft.startswith("text/") or ft in ("application/pdf",): + return "Document" + + if not ft.startswith("."): + ft = f".{ft}" + + for label, exts in FILETYPE_BUCKETS: + if ft in exts: + return label + return "Misc" + + def _list_children(parent: str = "") -> List[str]: """ Return the next folder level for the given parent. @@ -82,13 +134,35 @@ def _query_counts(folder_path: str) -> Dict[str, Any]: cursor = search_db.cursor() rows = cursor.execute(sql, params).fetchall() + type_rows = cursor.execute( + f""" + SELECT COALESCE(filetype, '') AS filetype_label, + COUNT(*) AS file_count + FROM files + WHERE {where_sql} + GROUP BY filetype_label + """, + params + ).fetchall() + total = sum(row["file_count"] for row in rows) categories = [ {"category": row["category_label"], "count": row["file_count"]} for row in rows ] - return {"total": total, "categories": categories} + type_totals: Dict[str, int] = {} + for row in type_rows: + bucket = _bucket_for_filetype(row["filetype_label"]) + type_totals[bucket] = type_totals.get(bucket, 0) + row["file_count"] + + filetypes = [ + {"type": label, "count": type_totals[label]} + for label in FILETYPE_ORDER + if type_totals.get(label) + ] + + return {"total": total, "categories": categories, "filetypes": filetypes} def search_db_analyzer(): diff --git a/static/search_db_analyzer.js b/static/search_db_analyzer.js index 950c8ad..46d28ff 100644 --- a/static/search_db_analyzer.js +++ b/static/search_db_analyzer.js @@ -20,6 +20,7 @@ const feedback = document.getElementById('analyzer-feedback'); const resultWrapper = document.getElementById('analyzer-result'); const resultBody = document.getElementById('result-body'); + const filetypeBody = document.getElementById('filetype-body'); const totalCount = document.getElementById('totalCount'); const levelsContainer = document.getElementById('folder-levels'); @@ -198,6 +199,9 @@ } resultBody.innerHTML = ''; + if (filetypeBody) { + filetypeBody.innerHTML = ''; + } if (data.categories && data.categories.length) { data.categories.forEach((row) => { const tr = document.createElement('tr'); @@ -219,6 +223,29 @@ resultBody.appendChild(tr); } + if (filetypeBody) { + if (data.filetypes && data.filetypes.length) { + data.filetypes.forEach((row) => { + const tr = document.createElement('tr'); + const type = document.createElement('td'); + const cnt = document.createElement('td'); + + type.textContent = row.type || 'Misc'; + cnt.textContent = row.count; + + tr.append(type, cnt); + filetypeBody.appendChild(tr); + }); + } else { + const tr = document.createElement('tr'); + const td = document.createElement('td'); + td.colSpan = 2; + td.textContent = 'Keine Datei-Typen gefunden.'; + tr.appendChild(td); + filetypeBody.appendChild(tr); + } + } + totalCount.textContent = `${data.total || 0} Dateien`; resultWrapper.style.display = 'block'; } catch (error) { diff --git a/templates/base.html b/templates/base.html index f972b62..e5c2cec 100644 --- a/templates/base.html +++ b/templates/base.html @@ -52,7 +52,7 @@
  • Verbindungen
  • Dateizugriffe
  • Wiederholungen
  • -
  • Dateiindex Analyse
  • +
  • Ordner auswerten
  • diff --git a/templates/search_db_analyzer.html b/templates/search_db_analyzer.html index 11587c1..7a49071 100644 --- a/templates/search_db_analyzer.html +++ b/templates/search_db_analyzer.html @@ -5,7 +5,7 @@ {% block content %}
    -

    Index auswerten

    +

    Ordner auswerten

    Ordner auswählen und die Anzahl der Dateien pro Kategorie aus der Dateiindex abrufen.

    @@ -28,16 +28,33 @@

    Ergebnis

    -
    - - - - - - - - -
    KategorieAnzahl Dateien
    +
    +
    +
    + + + + + + + + +
    KategorieAnzahl Dateien
    +
    +
    +
    +
    + + + + + + + + +
    DateitypAnzahl Dateien
    +
    +