import json import os import logging from urllib.parse import unquote def load_json(path): try: with open(path, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: logging.error(f"Erro ao carregar {path}: {e}") return {} def create_sample_index(manifest_path): """ Cria um índice onde a CHAVE é o nome do arquivo (ex: 'kick.wav') e o VALOR é uma lista de caminhos possíveis no servidor. """ manifest = load_json(manifest_path) sample_index = {} def traverse(node, current_path=""): for key, value in node.items(): if key == "_isFile": continue # Constrói o caminho relativo web-friendly (usando /) new_path = f"{current_path}/{key}" if current_path else key if isinstance(value, dict) and "_isFile" in value: # Normaliza o nome para minúsculo para busca insensível a caixa filename_key = key.lower() if filename_key in sample_index: sample_index[filename_key].append(new_path) else: sample_index[filename_key] = [new_path] elif isinstance(value, dict): traverse(value, new_path) traverse(manifest) return sample_index def check_dependencies(projects_json_path, manifest_path, output_report_path): logging.info("=== Iniciando Análise Profunda de Dependências ===") projects = load_json(projects_json_path) server_inventory = create_sample_index(manifest_path) report = { "summary": { "total": 0, "healthy": 0, # Tudo certo de primeira "recovered": 0, # Caminhos errados, mas arquivo encontrado no servidor "broken": 0, # Arquivo inexistente no servidor }, "projects": [], } for project in projects: # Ajuste a chave 'file_name' ou 'name' conforme seu parser p_name = project.get("file_name", "unknown") # Ajuste para onde seu parser guarda os samples (ex: 'instruments' ou 'samples') # Supondo que seu parser extraia uma lista de dicionários com 'src' p_samples = project.get("samples", []) project_status = { "name": p_name, "status": "HEALTHY", # HEALTHY | RECOVERED | BROKEN "dependencies": [], } has_missing = False has_remapped = False for sample in p_samples: # O caminho cru que vem do XML (ex: C:/Users/Jota/Desktop/kick.wav) raw_src = sample.get("src", "") if not raw_src: continue # 1. Normalização: Pega só o nome do arquivo (kick.wav) # unquote resolve caracteres de URL (%20 -> espaço) filename = os.path.basename(unquote(raw_src)) filename_key = filename.lower() dep_info = { "original_path": raw_src, "filename": filename, "status": "UNKNOWN", "server_path": None, } # 2. Verificação no Inventário do Servidor if filename_key in server_inventory: # Encontramos o arquivo no servidor! possible_paths = server_inventory[filename_key] # Pega o primeiro encontrado (Heurística simples) # Futuramente, poderia tentar casar a pasta pai para ser mais preciso dep_info["server_path"] = possible_paths[0] # Se o caminho original já era relativo e igual, é HEALTHY. # Se era absoluto (C:/...) ou diferente, é RECOVERED. if raw_src == possible_paths[0]: dep_info["status"] = "OK" else: dep_info["status"] = "REMAPPED" has_remapped = True else: # 3. O arquivo realmente não existe no servidor dep_info["status"] = "MISSING" has_missing = True project_status["dependencies"].append(dep_info) # Define o status final do projeto if has_missing: project_status["status"] = "BROKEN" report["summary"]["broken"] += 1 elif has_remapped: project_status["status"] = "RECOVERED" report["summary"]["recovered"] += 1 else: report["summary"]["healthy"] += 1 report["projects"].append(project_status) report["summary"]["total"] = len(projects) # Salva relatório os.makedirs(os.path.dirname(output_report_path), exist_ok=True) with open(output_report_path, "w", encoding="utf-8") as f: json.dump(report, f, indent=2, ensure_ascii=False) logging.info(f"Relatório salvo: {output_report_path}") logging.info(f"Resumo: {json.dumps(report['summary'], indent=2)}") return report