Skip to content

Instantly share code, notes, and snippets.

@fabriziosalmi
Created August 11, 2025 12:12
Show Gist options
  • Save fabriziosalmi/2242c04956d148cf201cc484fe8dc609 to your computer and use it in GitHub Desktop.
Save fabriziosalmi/2242c04956d148cf201cc484fe8dc609 to your computer and use it in GitHub Desktop.
index-all-bia
import os
import json
import argparse
import logging
from collections import defaultdict
from datetime import datetime
# --- CONFIGURAZIONE ---
# Percorso base da cui iniziare la scansione
BASE_PATH = "/mnt/user"
# Elenco delle directory di primo livello da escludere completamente
# Lo script controllerà se un percorso INIZIA con uno di questi.
EXCLUDE_DIRS = [
"appdata",
"domains",
"isos",
"Backup_Appdata",
"system",
"TUTTO",
"MUSICA",
"AUDIOLIBRI",
]
# Nome del file JSON di output
JSON_FILE_NAME = "media_index.json"
# Prefisso per il file di testo di output
TXT_FILE_PREFIX = "index"
# --------------------
def setup_logging(debug_mode: bool):
"""Configura il logging per l'applicazione."""
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 index_media(base_path: str, exclude_dirs: list, follow_links: bool):
"""
Scansiona le directory, indicizza i file e restituisce una struttura dati.
La struttura è un dizionario { "percorso_cartella": ["file1", "file2", ...] }.
"""
media_index = defaultdict(list)
total_files_count = 0
# Pre-calcola i percorsi completi da escludere per efficienza
full_exclude_paths = [os.path.join(base_path, d) for d in exclude_dirs]
logging.debug(f"Percorsi di esclusione completi: {full_exclude_paths}")
logging.info(f"Inizio scansione da '{base_path}'...")
logging.info(f"Seguire i link simbolici: {'Sì' if follow_links else 'No'}")
for root, dirs, files in os.walk(base_path, topdown=True, followlinks=follow_links):
# Escludi le directory specificate
# `topdown=True` permette di modificare `dirs` per potare l'albero di ricerca
if any(root.startswith(excluded_path) for excluded_path in full_exclude_paths):
logging.debug(f"Salto la directory esclusa e le sue sottodirectory: {root}")
dirs[:] = [] # Svuota la lista di sottodirectory per non visitarle
continue
if not files:
continue # Salta le cartelle che non contengono file
try:
# Aggiungiamo solo i file di questa directory all'indice
# I file vengono già ordinati per un output consistente
sorted_files = sorted(files)
media_index[root] = sorted_files
total_files_count += len(sorted_files)
# Log di progresso ogni 1000 cartelle indicizzate
if len(media_index) % 1000 == 0:
logging.info(f"Indicizzate {len(media_index)} cartelle e {total_files_count} file...")
except OSError as e:
logging.error(f"Errore di accesso durante la scansione di '{root}': {e}")
continue
logging.info(f"Scansione completata. Trovate {total_files_count} file in {len(media_index)} cartelle.")
return media_index
def save_json_index(index_data: dict, filename: str):
"""Salva l'indice in formato JSON."""
logging.info(f"Salvataggio dell'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 con successo.")
except IOError as e:
logging.error(f"Impossibile scrivere il file JSON '{filename}': {e}")
def save_txt_index(index_data: dict, filename_prefix: str):
"""Salva un report testuale formattato dell'indice."""
date_str = datetime.now().strftime("%Y-%m-%d")
filename = f"{filename_prefix}_{date_str}.txt"
logging.info(f"Creazione del report testuale in '{filename}'...")
try:
with open(filename, "w", encoding="utf-8") as out:
# Ordina le cartelle per percorso per un output pulito
for folder, files in sorted(index_data.items()):
# Corregge il percorso per rimuovere il prefisso base se non è "/"
display_folder = folder
if BASE_PATH != "/" and folder.startswith(BASE_PATH):
display_folder = folder[len(BASE_PATH):] or "/"
out.write(f"📁 {display_folder}\n")
for file in files: # i file sono già ordinati
out.write(f" - {file}\n")
out.write("\n")
logging.info(f"Report testuale creato con successo con {len(index_data)} cartelle.")
except IOError as e:
logging.error(f"Impossibile scrivere il file TXT '{filename}': {e}")
def main():
"""Funzione principale dello script."""
parser = argparse.ArgumentParser(
description="Indicizzatore di file multimediali per Unraid.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"--debug",
action="store_true",
help="Abilita il logging di debug dettagliato."
)
parser.add_argument(
"--follow-links",
action="store_true",
help="Segue i collegamenti simbolici durante la scansione."
)
args = parser.parse_args()
setup_logging(args.debug)
# Esegui l'indicizzazione
media_index = index_media(BASE_PATH, EXCLUDE_DIRS, args.follow_links)
if not media_index:
logging.warning("Nessun file trovato. L'indice non verrà creato.")
return
# Salva gli output
save_json_index(media_index, JSON_FILE_NAME)
save_txt_index(media_index, TXT_FILE_PREFIX)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment