teste padronização do nome dos projetos
This commit is contained in:
1 parent
46a4ab06de
commit
85b829f409
104 files changed
+822933
-329642
No files matched your search
+63
-43
@@ -8,7 +8,9 @@ import multiprocessing
|
||||
import logging
|
||||
import time
|
||||
import platform
|
||||
import sys # Adicionado para sair do script se faltar dependência
|
||||
import sys
|
||||
import re
|
||||
import unicodedata # ### NOVO: Para remover acentos
|
||||
from datetime import datetime
|
||||
|
||||
# Importando seus módulos
|
||||
@@ -28,6 +30,23 @@ from utils import (
|
||||
LOG_FOLDER,
|
||||
)
|
||||
|
||||
# ### NOVO: Função para padronizar nomes (igual ao Jekyll slugify) ###
|
||||
def slugify(value):
|
||||
"""
|
||||
Normaliza a string: remove acentos, converte para minúsculas,
|
||||
remove caracteres não alfanuméricos e substitui espaços por hifens.
|
||||
Ex: 'Ação & Reação!' -> 'acao-reacao'
|
||||
"""
|
||||
value = str(value)
|
||||
# Normaliza unicode (ex: ã -> a)
|
||||
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
|
||||
value = value.lower()
|
||||
# Remove tudo que não for letra, número ou espaço/hífen
|
||||
value = re.sub(r'[^\w\s-]', '', value)
|
||||
# Substitui espaços e underlines por hífen
|
||||
value = re.sub(r'[-\s_]+', '-', value)
|
||||
return value.strip('-_')
|
||||
|
||||
def check_system_dependencies():
|
||||
"""Verifica se as ferramentas necessárias estão instaladas antes de iniciar."""
|
||||
required_tools = ["lmms"]
|
||||
@@ -39,18 +58,17 @@ def check_system_dependencies():
|
||||
if missing:
|
||||
logging.critical(f"FERRAMENTAS FALTANDO: {', '.join(missing)}")
|
||||
logging.critical("Por favor instale: sudo apt-get install " + " ".join(missing))
|
||||
sys.exit(1) # Encerra o script imediatamente
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_linux_mem_info():
|
||||
"""Lê /proc/meminfo para obter memória total de forma nativa no Linux."""
|
||||
try:
|
||||
with open("/proc/meminfo", "r") as f:
|
||||
for line in f:
|
||||
if "MemTotal" in line:
|
||||
kb_value = int(line.split()[1])
|
||||
return kb_value / (1024 * 1024)
|
||||
except (IOError, ValueError): # Melhoria: Captura apenas erros de arquivo/valor
|
||||
except (IOError, ValueError):
|
||||
return 0
|
||||
except Exception as e:
|
||||
logging.warning(f"Erro ao ler memória: {e}")
|
||||
@@ -58,7 +76,6 @@ def get_linux_mem_info():
|
||||
|
||||
|
||||
def get_cpu_model_name():
|
||||
"""Lê /proc/cpuinfo para pegar o nome real do processador."""
|
||||
try:
|
||||
with open("/proc/cpuinfo", "r") as f:
|
||||
for line in f:
|
||||
@@ -69,7 +86,6 @@ def get_cpu_model_name():
|
||||
|
||||
|
||||
def log_system_info():
|
||||
# Apenas certifique-se de manter a indentação correta
|
||||
try:
|
||||
logging.info("=" * 30)
|
||||
logging.info("AUDITORIA DE AMBIENTE (HARDWARE)")
|
||||
@@ -109,55 +125,59 @@ def setup_logger():
|
||||
|
||||
|
||||
def process_single_file(file_name):
|
||||
"""Worker robusto com melhor tratamento de Subprocesso."""
|
||||
"""Worker robusto com padronização de nomes (Slugify)."""
|
||||
file_path = os.path.join(MMP_FOLDER, file_name)
|
||||
pid = os.getpid()
|
||||
result = {"success": False, "file": file_name, "data": None, "error": None}
|
||||
|
||||
# ### NOVO: Calcula os nomes sanitizados no início ###
|
||||
original_base_name = os.path.splitext(file_name)[0]
|
||||
clean_slug = slugify(original_base_name)
|
||||
|
||||
# Define os nomes de saída baseados no Slug
|
||||
wav_name = clean_slug + ".wav"
|
||||
json_name = clean_slug + ".json"
|
||||
yml_name = clean_slug + ".yml"
|
||||
|
||||
try:
|
||||
logging.info(f"[PID {pid}] Processando: {file_name}")
|
||||
logging.info(f"[PID {pid}] Processando: {file_name} -> Slug: {clean_slug}")
|
||||
|
||||
# 1. Tratamento MMPZ
|
||||
if file_name.endswith(".mmpz"):
|
||||
destination_path = os.path.join(MMPZ_FOLDER, file_name)
|
||||
|
||||
# Move arquivo se necessário
|
||||
if not os.path.exists(destination_path):
|
||||
shutil.move(file_path, destination_path)
|
||||
elif os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
mmp_name = os.path.splitext(file_name)[0] + ".mmp"
|
||||
output_mmp_path = os.path.join(MMP_FOLDER, mmp_name)
|
||||
# O dump precisa ser um arquivo temporário ou manter o nome original para processamento interno
|
||||
# mas vamos manter o fluxo original de dump para parsing
|
||||
mmp_temp_name = original_base_name + ".mmp"
|
||||
output_mmp_path = os.path.join(MMP_FOLDER, mmp_temp_name)
|
||||
|
||||
# Usa caminho absoluto para evitar erros do LMMS
|
||||
abs_dest = os.path.abspath(destination_path)
|
||||
abs_mmp_out = os.path.abspath(output_mmp_path)
|
||||
|
||||
# Lista ao invés de string (Sem shell=True)
|
||||
# Comando dump: LMMS escreve no stdout, então precisamos capturar
|
||||
dump_cmd = ["lmms", "--dump", abs_dest]
|
||||
|
||||
try:
|
||||
with open(abs_mmp_out, "w") as outfile:
|
||||
subprocess.run(
|
||||
dump_cmd,
|
||||
stdout=outfile, # Redireciona saida direto pro arquivo
|
||||
stderr=subprocess.PIPE, # Captura erros
|
||||
stdout=outfile,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True,
|
||||
env={"QT_QPA_PLATFORM": "offscreen", **os.environ},
|
||||
)
|
||||
logging.info(f"[PID {pid}] Dump MMP criado.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
result["error"] = f"Erro no dump MMP: {e.stderr.decode('utf-8')}"
|
||||
logging.error(f"[PID {pid}] {result['error']}")
|
||||
return result
|
||||
|
||||
# Conversão WAV
|
||||
wav_name = os.path.splitext(file_name)[0] + ".wav"
|
||||
# ### ALTERADO: Geração do WAV usa o nome sanitizado ###
|
||||
abs_wav_out = os.path.abspath(os.path.join(WAV_FOLDER, wav_name))
|
||||
|
||||
# Comando em lista: Mais seguro e organizado
|
||||
wav_cmd = [
|
||||
"lmms",
|
||||
"-r",
|
||||
@@ -170,31 +190,43 @@ def process_single_file(file_name):
|
||||
|
||||
try:
|
||||
subprocess.run(wav_cmd, check=True, capture_output=True, text=True)
|
||||
# Log em vez de Print
|
||||
logging.info(f"[PID {pid}] Áudio WAV gerado com sucesso.")
|
||||
logging.info(f"[PID {pid}] Áudio WAV gerado: {wav_name}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Não paramos o fluxo por erro no WAV, mas logamos como erro
|
||||
logging.warning(f"[PID {pid}] Falha no WAV: {e.stderr}")
|
||||
|
||||
# Define o caminho para o parser
|
||||
file_to_parse = output_mmp_path
|
||||
|
||||
elif file_name.endswith(".mmp"):
|
||||
file_to_parse = file_path
|
||||
|
||||
# Se for apenas MMP, geramos o wav também se não existir?
|
||||
# O código original não gerava WAV para .mmp puros explicitamente aqui,
|
||||
# mas assumindo que segue a lógica do mmpz:
|
||||
# (Adicione logica de render wav p/ mmp puro se necessário aqui)
|
||||
|
||||
# 2. Parsing e Salvamento
|
||||
if os.path.exists(file_to_parse):
|
||||
mmp_data = parse_mmp_file(file_to_parse)
|
||||
|
||||
if mmp_data:
|
||||
base_name = os.path.splitext(file_name)[0]
|
||||
# ### NOVO: Injeta metadados de padronização ###
|
||||
# Substitui o nome do arquivo nos dados pelo slug (para links funcionarem)
|
||||
mmp_data["file"] = clean_slug
|
||||
# Adiciona o título original para exibição bonita na tela
|
||||
mmp_data["original_title"] = original_base_name
|
||||
|
||||
# Salva usando os nomes sanitizados
|
||||
save_to_json(
|
||||
mmp_data, os.path.join(METADATA_FOLDER, base_name + ".json")
|
||||
mmp_data, os.path.join(METADATA_FOLDER, json_name)
|
||||
)
|
||||
save_to_yaml(mmp_data, os.path.join(DATA_FOLDER, base_name + ".yml"))
|
||||
save_to_yaml(mmp_data, os.path.join(DATA_FOLDER, yml_name))
|
||||
|
||||
result["success"] = True
|
||||
result["data"] = mmp_data
|
||||
|
||||
# Limpeza do mmp temporário gerado do dump (opcional, para não lotar a pasta)
|
||||
if file_name.endswith(".mmpz") and os.path.exists(file_to_parse):
|
||||
os.remove(file_to_parse)
|
||||
else:
|
||||
result["error"] = "Dados vazios após parsing."
|
||||
else:
|
||||
@@ -211,11 +243,10 @@ def main_parallel():
|
||||
logger, log_file_path = setup_logger()
|
||||
start_time = time.time()
|
||||
|
||||
# MELHORIA 4: Fail Fast
|
||||
check_system_dependencies()
|
||||
|
||||
log_system_info()
|
||||
logging.info("=== Iniciando Pipeline Otimizado ===")
|
||||
logging.info("=== Iniciando Pipeline Otimizado (Com Sanitização) ===")
|
||||
|
||||
create_folders_if_not_exist([MMPZ_FOLDER, WAV_FOLDER, METADATA_FOLDER, DATA_FOLDER])
|
||||
|
||||
@@ -235,7 +266,6 @@ def main_parallel():
|
||||
with multiprocessing.Pool(processes=num_cores) as pool:
|
||||
results = pool.map(process_single_file, all_files)
|
||||
|
||||
# Processamento de resultados (igual ao seu)
|
||||
successful_data = [r["data"] for r in results if r["success"]]
|
||||
failed_files = [r for r in results if not r["success"]]
|
||||
|
||||
@@ -243,13 +273,11 @@ def main_parallel():
|
||||
save_to_json(successful_data, os.path.join(METADATA_FOLDER, "all.json"))
|
||||
save_to_yaml(successful_data, os.path.join(DATA_FOLDER, "all.yml"))
|
||||
|
||||
# Geração de Manifestos
|
||||
try:
|
||||
manifest_report = generate_manifests(SRC_MMPSEARCH)
|
||||
except Exception as e:
|
||||
manifest_report = {"generated": [], "failed": [str(e)]}
|
||||
|
||||
# Relatório Final
|
||||
duration = time.time() - start_time
|
||||
logging.info("=" * 60)
|
||||
logging.info(
|
||||
@@ -261,7 +289,6 @@ def main_parallel():
|
||||
for f in failed_files:
|
||||
logging.error(f"{f['file']}: {f['error']}")
|
||||
|
||||
# Verificação de Dependências (Projetos)
|
||||
try:
|
||||
check_dependencies(
|
||||
os.path.join(METADATA_FOLDER, "all.json"),
|
||||
@@ -269,17 +296,12 @@ def main_parallel():
|
||||
os.path.join(METADATA_FOLDER, "dependency_report.json"),
|
||||
)
|
||||
except Exception:
|
||||
pass # Erro já logado na função ou irrelevante se arquivos não existirem
|
||||
pass
|
||||
|
||||
|
||||
def rebuild_indexes():
|
||||
"""
|
||||
Função auxiliar para regerar all.json e all.yml baseada nos arquivos processados.
|
||||
Pode ser chamada pela API após um upload.
|
||||
"""
|
||||
logging.info("Regerando índices globais (all.json / all.yml)...")
|
||||
|
||||
# Lista todos os JSONs individuais na pasta metadata (exceto os manifestos e o all.json)
|
||||
all_data = []
|
||||
ignored_files = [
|
||||
"all.json",
|
||||
@@ -295,9 +317,7 @@ def rebuild_indexes():
|
||||
with open(
|
||||
os.path.join(METADATA_FOLDER, f), "r", encoding="utf-8"
|
||||
) as json_file:
|
||||
data = json.load(
|
||||
json_file
|
||||
) # Precisa importar json no topo se não tiver
|
||||
data = json.load(json_file)
|
||||
all_data.append(data)
|
||||
except Exception as e:
|
||||
logging.error(f"Erro ao ler {f} para índice global: {e}")
|
||||
@@ -311,4 +331,4 @@ def rebuild_indexes():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main_parallel()
|
||||
main_parallel()
|
||||
Reference in new issue
Block a user