Skip to content

Instantly share code, notes, and snippets.

@fabriziosalmi
Created August 11, 2025 12:15
Show Gist options
  • Save fabriziosalmi/c53556327a1c8a9562549efa8b7c095e to your computer and use it in GitHub Desktop.
Save fabriziosalmi/c53556327a1c8a9562549efa8b7c095e to your computer and use it in GitHub Desktop.
index all bia 2
import os
import json
import argparse
import logging
import sqlite3
from collections import defaultdict
from datetime import datetime
from tqdm import tqdm # Importa tqdm per la progress bar
# --- CONFIGURAZIONE ---
BASE_PATH = "/mnt/user"
EXCLUDE_DIRS = [
"appdata", "domains", "isos", "Backup_Appdata", "system",
"TUTTO", "MUSICA", "AUDIOLIBRI",
]
# Nomi dei file di output
DB_FILE_NAME = "media_index.db"
JSON_FILE_NAME = "media_index.json"
TXT_FILE_PREFIX = "index"
# --------------------
def setup_logging(debug_mode: bool):
"""Configura il logging."""
level = logging.DEBUG if debug_mode else logging.INFO
logging.basicConfig(
level=level,
format="[%(asctime)s] [%(levelname)s] - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
def setup_database(db_path: str):
"""Crea la tabella nel database SQLite se non esiste."""
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Una tabella semplice per memorizzare percorsi e file
# L'indice su 'path' velocizzerà le future ricerche
cursor.execute("""
CREATE TABLE IF NOT EXISTS files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT NOT NULL,
filename TEXT NOT NULL,
UNIQUE(path, filename)
);
""")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_path ON files (path);")
# Pulisci la tabella per un nuovo inserimento
cursor.execute("DELETE FROM files;")
conn.commit()
return conn
except sqlite3.Error as e:
logging.error(f"Errore del database SQLite: {e}")
return None
def index_media_and_save(base_path, exclude_dirs, follow_links, output_format):
"""
Scansiona le directory e salva i risultati direttamente nel formato scelto
per minimizzare l'uso della memoria.
"""
full_exclude_paths = [os.path.join(base_path, d) for d in exclude_dirs]
logging.info(f"Inizio scansione da '{base_path}'. Formato output: {output_format}")
# Prepara connessione al DB se necessario
conn = None
cursor = None
if output_format in ["sqlite", "all"]:
conn = setup_database(DB_FILE_NAME)
if conn:
cursor = conn.cursor()
else:
# Se il DB fallisce, non procedere con l'output sqlite
output_format = "json" if output_format == "all" else "none"
# Struttura dati in memoria solo se richiesta
in_memory_index = defaultdict(list) if output_format in ["json", "txt", "all"] else None
total_files_count = 0
# Usiamo un iteratore per poterlo passare a tqdm
walker = os.walk(base_path, topdown=True, followlinks=follow_links)
# tqdm mostra una barra di avanzamento dinamica
for root, dirs, files in tqdm(walker, desc="Scansione cartelle", unit="dir"):
if any(root.startswith(ex_path) for ex_path in full_exclude_paths):
dirs[:] = []
continue
if not files:
continue
sorted_files = sorted(files)
# Salva in memoria se necessario
if in_memory_index is not None:
in_memory_index[root] = sorted_files
# Salva direttamente su SQLite
if cursor:
try:
# Usa executemany per un inserimento in blocco, molto più veloce
entries_to_insert = [(root, f) for f in sorted_files]
cursor.executemany("INSERT INTO files (path, filename) VALUES (?, ?)", entries_to_insert)
except sqlite3.Error as e:
logging.error(f"Errore inserimento dati per la cartella {root}: {e}")
total_files_count += len(sorted_files)
if conn:
conn.commit()
conn.close()
logging.info(f"Dati salvati con successo nel database '{DB_FILE_NAME}'.")
logging.info(f"Scansione completata. Trovati {total_files_count} file in {len(in_memory_index) if in_memory_index is not None else 'N/A'} cartelle.")
# Gestione output finali da dati in memoria
if output_format in ["json", "all"]:
save_json_index(in_memory_index, JSON_FILE_NAME)
if output_format in ["txt", "all"]:
save_txt_index(in_memory_index, TXT_FILE_PREFIX)
def save_json_index(index_data, filename):
"""Salva l'indice in formato JSON."""
logging.info(f"Salvataggio indice JSON in '{filename}'...")
try:
with open(filename, "w", encoding="utf-8") as f:
json.dump(index_data, f, ensure_ascii=False, indent=2)
logging.info("Indice JSON salvato.")
except IOError as e:
logging.error(f"Impossibile scrivere il file JSON '{filename}': {e}")
def save_txt_index(index_data, filename_prefix):
"""Salva un report testuale formattato."""
date_str = datetime.now().strftime("%Y-%m-%d")
filename = f"{filename_prefix}_{date_str}.txt"
logging.info(f"Creazione report TXT in '{filename}'...")
try:
with open(filename, "w", encoding="utf-8") as out:
for folder, files in sorted(index_data.items()):
display_folder = folder.replace(BASE_PATH, "", 1) or "/"
out.write(f"📁 {display_folder}\n")
for file in files:
out.write(f" - {file}\n")
out.write("\n")
logging.info(f"Report TXT creato con {len(index_data)} cartelle.")
except IOError as e:
logging.error(f"Impossibile scrivere il file TXT '{filename}': {e}")
def main():
parser = argparse.ArgumentParser(description="Indicizzatore di file per Unraid.")
parser.add_argument("--debug", action="store_true", help="Abilita log dettagliati.")
parser.add_argument("--follow-links", action="store_true", help="Segue i link simbolici.")
parser.add_argument(
"--output-format",
choices=["json", "txt", "sqlite", "all"],
default="all",
help="Scegli il formato di output."
)
args = parser.parse_args()
setup_logging(args.debug)
index_media_and_save(BASE_PATH, EXCLUDE_DIRS, args.follow_links, args.output_format)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment