improve analyzer
This commit is contained in:
parent
6a27d47222
commit
c855bfdbc1
@ -10,6 +10,32 @@ APP_CONFIG = auth.return_app_config()
|
|||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
SEARCH_DB_PATH = os.path.join(BASE_DIR, "search.db")
|
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.
|
# 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 = sqlite3.connect(f"file:{SEARCH_DB_PATH}?mode=ro", uri=True, check_same_thread=False)
|
||||||
search_db.row_factory = sqlite3.Row
|
search_db.row_factory = sqlite3.Row
|
||||||
@ -20,6 +46,32 @@ def _normalize_folder_path(folder_path: str) -> str:
|
|||||||
return folder_path.replace("\\", "/").strip().strip("/")
|
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]:
|
def _list_children(parent: str = "") -> List[str]:
|
||||||
"""
|
"""
|
||||||
Return the next folder level for the given parent.
|
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()
|
cursor = search_db.cursor()
|
||||||
rows = cursor.execute(sql, params).fetchall()
|
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)
|
total = sum(row["file_count"] for row in rows)
|
||||||
categories = [
|
categories = [
|
||||||
{"category": row["category_label"], "count": row["file_count"]}
|
{"category": row["category_label"], "count": row["file_count"]}
|
||||||
for row in rows
|
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():
|
def search_db_analyzer():
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
const feedback = document.getElementById('analyzer-feedback');
|
const feedback = document.getElementById('analyzer-feedback');
|
||||||
const resultWrapper = document.getElementById('analyzer-result');
|
const resultWrapper = document.getElementById('analyzer-result');
|
||||||
const resultBody = document.getElementById('result-body');
|
const resultBody = document.getElementById('result-body');
|
||||||
|
const filetypeBody = document.getElementById('filetype-body');
|
||||||
const totalCount = document.getElementById('totalCount');
|
const totalCount = document.getElementById('totalCount');
|
||||||
const levelsContainer = document.getElementById('folder-levels');
|
const levelsContainer = document.getElementById('folder-levels');
|
||||||
|
|
||||||
@ -198,6 +199,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
resultBody.innerHTML = '';
|
resultBody.innerHTML = '';
|
||||||
|
if (filetypeBody) {
|
||||||
|
filetypeBody.innerHTML = '';
|
||||||
|
}
|
||||||
if (data.categories && data.categories.length) {
|
if (data.categories && data.categories.length) {
|
||||||
data.categories.forEach((row) => {
|
data.categories.forEach((row) => {
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
@ -219,6 +223,29 @@
|
|||||||
resultBody.appendChild(tr);
|
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`;
|
totalCount.textContent = `${data.total || 0} Dateien`;
|
||||||
resultWrapper.style.display = 'block';
|
resultWrapper.style.display = 'block';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
<li><a class="dropdown-item" href="{{ url_for('connections') }}" data-ajax-nav>Verbindungen</a></li>
|
<li><a class="dropdown-item" href="{{ url_for('connections') }}" data-ajax-nav>Verbindungen</a></li>
|
||||||
<li><a class="dropdown-item" href="{{ url_for('file_access') }}" data-ajax-nav>Dateizugriffe</a></li>
|
<li><a class="dropdown-item" href="{{ url_for('file_access') }}" data-ajax-nav>Dateizugriffe</a></li>
|
||||||
<li><a class="dropdown-item" href="{{ url_for('songs_dashboard') }}" data-ajax-nav>Wiederholungen</a></li>
|
<li><a class="dropdown-item" href="{{ url_for('songs_dashboard') }}" data-ajax-nav>Wiederholungen</a></li>
|
||||||
<li><a class="dropdown-item" href="{{ url_for('search_db_analyzer') }}" data-ajax-nav>Dateiindex Analyse</a></li>
|
<li><a class="dropdown-item" href="{{ url_for('search_db_analyzer') }}" data-ajax-nav>Ordner auswerten</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>Index auswerten</h2>
|
<h2>Ordner auswerten</h2>
|
||||||
<p class="text-muted">
|
<p class="text-muted">
|
||||||
Ordner auswählen und die Anzahl der Dateien pro Kategorie aus der Dateiindex abrufen.
|
Ordner auswählen und die Anzahl der Dateien pro Kategorie aus der Dateiindex abrufen.
|
||||||
</p>
|
</p>
|
||||||
@ -28,16 +28,33 @@
|
|||||||
<h4 class="mb-0">Ergebnis</h4>
|
<h4 class="mb-0">Ergebnis</h4>
|
||||||
<span class="badge bg-secondary" id="totalCount"></span>
|
<span class="badge bg-secondary" id="totalCount"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="row g-3">
|
||||||
<table class="table table-striped align-middle">
|
<div class="col-lg-7">
|
||||||
<thead>
|
<div class="table-responsive">
|
||||||
<tr>
|
<table class="table table-striped align-middle">
|
||||||
<th>Kategorie</th>
|
<thead>
|
||||||
<th>Anzahl Dateien</th>
|
<tr>
|
||||||
</tr>
|
<th>Kategorie</th>
|
||||||
</thead>
|
<th>Anzahl Dateien</th>
|
||||||
<tbody id="result-body"></tbody>
|
</tr>
|
||||||
</table>
|
</thead>
|
||||||
|
<tbody id="result-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Dateityp</th>
|
||||||
|
<th>Anzahl Dateien</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="filetype-body"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user