Afegit: media_mover.py
Retocat: fbneo_roms_by_manufacturer.py
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
# Fichero a usar en caso de no especificar ninguno por parametro
|
||||
XML_FILE="FinalBurn Neo v1.0.0.02 (ClrMame Pro XML).dat"
|
||||
|
||||
# Opciones globales
|
||||
IGNORE_LIST = ["DECO Cassette", "Bootleg", "prototype", "Quiz", "Mahjong", "Demo"]
|
||||
IGNORE_SYSTEM = ["neogeo"]
|
||||
|
||||
# Directorio de entrada a usar en caso de no especificar ninguno por parametro
|
||||
INPUT_FOLDER="/sustancia/roms/FB Neo v1.0.0.2/roms/arcade"
|
||||
|
||||
# Directorio de salida a usar en caso de no especificar ninguno por parametro
|
||||
OUTPUT_FOLDER="/home/sergio/tmp"
|
||||
@@ -0,0 +1,310 @@
|
||||
# Script para copiar roms a partir de un xml de fbneo
|
||||
# Copia las roms por desarrollador y sin clones
|
||||
|
||||
# Por hacer:
|
||||
# pasar por parametro si se quieren clones
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import argparse
|
||||
import config
|
||||
from xml.dom import minidom
|
||||
|
||||
def normalize_path(path):
|
||||
"""Elimina los caracteres ilegales de la cadena de texto"""
|
||||
# Lista de caracteres ilegales que deben ser eliminados
|
||||
illegal_chars = ["<", ">", ":", '"', "/", "\\", "|", "?", "*"]
|
||||
# Carácter de reemplazo
|
||||
replace_with = "_"
|
||||
|
||||
# Reemplaza cada carácter ilegal en la cadena de texto
|
||||
for char in illegal_chars:
|
||||
path = path.replace(char, replace_with)
|
||||
|
||||
return path
|
||||
|
||||
def parse_arguments():
|
||||
"""Parsea los argumentos de la línea de comandos"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Gestiona las roms de fbneo por desarrolladores a partir de un fichero .dat"
|
||||
)
|
||||
|
||||
# Grupo de argumentos mutuos exclusivos
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
"-l",
|
||||
"--list",
|
||||
help="Muestra la lista de desarrolladores o de juegos",
|
||||
action="store_true",
|
||||
)
|
||||
group.add_argument(
|
||||
"-c",
|
||||
"--copy",
|
||||
help="Copia las roms",
|
||||
action="store_true"
|
||||
)
|
||||
group.add_argument(
|
||||
"-f",
|
||||
"--find",
|
||||
help="Busca juegos que contengan la cadena de texto especificada",
|
||||
)
|
||||
|
||||
# Otros argumentos
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--sort",
|
||||
help="Ordena los resultados por carpetas de desarrollador al copiar todas las roms",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-cf",
|
||||
"--create_folder",
|
||||
help="Copia las roms dentro de la carpeta del desarrollador",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
"--manufacturer",
|
||||
help="Selecciona un desarrollador"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--dat",
|
||||
help="Ruta del fichero .dat con información de las roms"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--input",
|
||||
help="Ruta donde se encuentran las roms",
|
||||
default=""
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--output",
|
||||
help="Ruta donde depositar las roms",
|
||||
default=""
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
def load_dat_file(dat_path):
|
||||
"""Carga y analiza el fichero .dat especificado"""
|
||||
if not dat_path:
|
||||
print("No se ha especificado un fichero .dat")
|
||||
if os.path.exists(config.XML_FILE):
|
||||
# Usa el fichero por defecto si no se especifica uno
|
||||
print(f"Usando el fichero por defecto: {config.XML_FILE}")
|
||||
dat_path = config.XML_FILE
|
||||
else:
|
||||
# Salir si no se encuentra el fichero por defecto
|
||||
sys.exit(2)
|
||||
elif not os.path.isfile(dat_path):
|
||||
# Salir si el fichero especificado no existe
|
||||
print(f"No se encuentra el fichero .dat especificado: {dat_path}")
|
||||
sys.exit(2)
|
||||
|
||||
print(f"Analizando el fichero {dat_path}")
|
||||
return minidom.parse(dat_path)
|
||||
|
||||
def list_manufacturers(file):
|
||||
"""Lista todos los desarrolladores presentes en el fichero .dat"""
|
||||
print("Lista de todos los desarrolladores:")
|
||||
|
||||
manufacturers = []
|
||||
games = file.getElementsByTagName("game")
|
||||
|
||||
# Recoge todos los desarrolladores de los juegos
|
||||
for game in games:
|
||||
manufacturer = game.getElementsByTagName("manufacturer")[0]
|
||||
manufacturers.append(manufacturer.firstChild.data)
|
||||
|
||||
# Elimina los duplicados
|
||||
manufacturers = list(dict.fromkeys(manufacturers))
|
||||
# Ordena alfabéticamente la lista de desarrolladores
|
||||
manufacturers.sort()
|
||||
|
||||
# Imprime cada desarrollador en una nueva línea
|
||||
for manufacturer in manufacturers:
|
||||
print(manufacturer)
|
||||
|
||||
def list_games_by_manufacturer(file, manufacturer):
|
||||
"""Lista todos los juegos de un desarrollador específico"""
|
||||
games = file.getElementsByTagName("game")
|
||||
filtered_games = []
|
||||
|
||||
# Filtra los juegos según el fabricante especificado y excluye clones y BIOS
|
||||
for game in games:
|
||||
cloneof = game.getAttribute("cloneof")
|
||||
isbios = game.getAttribute("isbios")
|
||||
game_manufacturer = game.getElementsByTagName("manufacturer")[0]
|
||||
description = game.getElementsByTagName("description")[0]
|
||||
if (
|
||||
(game_manufacturer.firstChild.data == manufacturer or manufacturer == 'all')
|
||||
and not cloneof
|
||||
and not isbios
|
||||
):
|
||||
filtered_games.append((description.firstChild.data, game.getAttribute('name'), game_manufacturer.firstChild.data))
|
||||
|
||||
# Encuentra el ancho máximo para cada columna
|
||||
max_desc_length = max(len("Descripción"), max(len(row[0]) for row in filtered_games))
|
||||
max_name_length = max(len("Nombre del archivo"), max(len(row[1] + '.zip') for row in filtered_games))
|
||||
max_manufacturer_length = max(len("Desarrollador"), max(len(row[2]) for row in filtered_games))
|
||||
|
||||
# Imprime el encabezado de la tabla
|
||||
print(f"Lista de todos los juegos de {manufacturer}: {len(filtered_games)}")
|
||||
print(f"{'='*(max_desc_length+max_name_length+max_manufacturer_length+10)}")
|
||||
print(f"| {'Descripción':<{max_desc_length}} | {'Nombre del archivo':<{max_name_length}} | {'Desarrollador':<{max_manufacturer_length}} |")
|
||||
print(f"|{'-'*(max_desc_length+2)}|{'-'*(max_name_length+2)}|{'-'*(max_manufacturer_length+2)}|")
|
||||
|
||||
# Imprime cada juego en la tabla
|
||||
for description, name, game_manufacturer in filtered_games:
|
||||
print(f"| {description:<{max_desc_length}} | {name + '.zip':<{max_name_length}} | {game_manufacturer:<{max_manufacturer_length}} |")
|
||||
|
||||
# Imprime el pie de la tabla
|
||||
print(f"{'='*(max_desc_length+max_name_length+max_manufacturer_length+10)}")
|
||||
|
||||
def find_games(file, search_string):
|
||||
"""Busca juegos que contengan la cadena de texto especificada"""
|
||||
games = file.getElementsByTagName("game")
|
||||
filtered_games = []
|
||||
|
||||
# Filtra los juegos según la cadena de búsqueda especificada
|
||||
for game in games:
|
||||
description = game.getElementsByTagName("description")[0]
|
||||
if search_string.casefold() in description.firstChild.data.casefold():
|
||||
game_manufacturer = game.getElementsByTagName("manufacturer")[0]
|
||||
filtered_games.append((description.firstChild.data, game.getAttribute('name'), game_manufacturer.firstChild.data))
|
||||
|
||||
# Encuentra el ancho máximo para cada columna
|
||||
max_desc_length = max(len("Descripción"), max(len(row[0]) for row in filtered_games))
|
||||
max_name_length = max(len("Nombre del archivo"), max(len(row[1] + '.zip') for row in filtered_games))
|
||||
max_manufacturer_length = max(len("Desarrollador"), max(len(row[2]) for row in filtered_games))
|
||||
|
||||
# Imprime el encabezado de la tabla
|
||||
print(f"Juegos que contienen '{search_string}': {len(filtered_games)}")
|
||||
print(f"{'='*(max_desc_length+max_name_length+max_manufacturer_length+10)}")
|
||||
print(f"| {'Descripción':<{max_desc_length}} | {'Nombre del archivo':<{max_name_length}} | {'Desarrollador':<{max_manufacturer_length}} |")
|
||||
print(f"|{'-'*(max_desc_length+2)}|{'-'*(max_name_length+2)}|{'-'*(max_manufacturer_length+2)}|")
|
||||
|
||||
# Imprime cada juego en la tabla
|
||||
for description, name, game_manufacturer in filtered_games:
|
||||
print(f"| {description:<{max_desc_length}} | {name + '.zip':<{max_name_length}} | {game_manufacturer:<{max_manufacturer_length}} |")
|
||||
|
||||
# Imprime el pie de la tabla
|
||||
print(f"{'='*(max_desc_length+max_name_length+max_manufacturer_length+10)}")
|
||||
|
||||
def copy_games(file, args, all_games=False):
|
||||
"""Copia los juegos según los criterios especificados"""
|
||||
if args.create_folder and not all_games:
|
||||
# Normaliza el nombre del desarrollador para usarlo como nombre de carpeta
|
||||
normalized_manufacturer = normalize_path(args.manufacturer)
|
||||
os.mkdir(os.path.join(args.output, args.manufacturer))
|
||||
|
||||
# Listas para almacenar los juegos no encontrados, ignorados y copiados
|
||||
notfound = []
|
||||
ignored_games = []
|
||||
copied_games = []
|
||||
|
||||
games = file.getElementsByTagName("game")
|
||||
|
||||
if all_games:
|
||||
print(f"Copiando todos los juegos: {len(games)}")
|
||||
else:
|
||||
print(f"Copiando todos los juegos de {args.manufacturer}: {len(games)}")
|
||||
|
||||
for game in games:
|
||||
isignored = False
|
||||
name = game.getAttribute("name") + ".zip"
|
||||
cloneof = game.getAttribute("cloneof")
|
||||
isbios = game.getAttribute("isbios")
|
||||
romof = game.getAttribute("romof")
|
||||
manufacturer = game.getElementsByTagName("manufacturer")[0]
|
||||
description = game.getElementsByTagName("description")[0]
|
||||
driver = game.getElementsByTagName("driver")
|
||||
status = (
|
||||
game.getElementsByTagName("driver")[0].getAttribute("status")
|
||||
if driver
|
||||
else ""
|
||||
)
|
||||
|
||||
# Verifica si el juego cumple con los criterios para ser copiado
|
||||
if (all_games or manufacturer.firstChild.data == args.manufacturer) and not cloneof and not isbios and status == "good":
|
||||
# Verifica si el juego debe ser ignorado
|
||||
for ignore_element in config.IGNORE_LIST:
|
||||
if ignore_element.casefold() in description.firstChild.data.casefold():
|
||||
ignored_games.append(description.firstChild.data)
|
||||
isignored = True
|
||||
|
||||
for ignore_element in config.IGNORE_SYSTEM:
|
||||
if ignore_element.casefold() in romof.casefold():
|
||||
ignored_games.append(description.firstChild.data)
|
||||
isignored = True
|
||||
|
||||
if not isignored:
|
||||
# Define la ruta de origen y destino del archivo
|
||||
src = os.path.join(args.input, name)
|
||||
if args.sort:
|
||||
x = manufacturer.firstChild.data
|
||||
x = x.replace(r"/", r"-")
|
||||
dst = os.path.join(args.output, x, name)
|
||||
if not os.path.isdir(os.path.join(args.output, x)):
|
||||
os.mkdir(os.path.join(args.output, x))
|
||||
else:
|
||||
if args.create_folder and not all_games:
|
||||
dst = os.path.join(args.output, normalized_manufacturer, name)
|
||||
else:
|
||||
dst = os.path.join(args.output, name)
|
||||
|
||||
# Copia el archivo si existe en la ruta de origen
|
||||
if os.path.isfile(src):
|
||||
shutil.copyfile(src, dst)
|
||||
copied_games.append(description.firstChild.data)
|
||||
print(description.firstChild.data)
|
||||
else:
|
||||
notfound.append(description.firstChild.data)
|
||||
|
||||
# Imprime los resultados de los juegos no encontrados, ignorados y copiados
|
||||
print(f"\nJuegos faltantes: {len(notfound)}")
|
||||
for game in notfound:
|
||||
print(game)
|
||||
|
||||
print(f"\nJuegos ignorados: {len(ignored_games)}")
|
||||
for game in ignored_games:
|
||||
print(game)
|
||||
|
||||
print(f"\nJuegos copiados: {len(copied_games)}")
|
||||
print(f"Juegos faltantes: {len(notfound)}")
|
||||
print(f"Juegos ignorados: {len(ignored_games)}")
|
||||
|
||||
def main():
|
||||
"""Función principal que coordina la ejecución del script"""
|
||||
# Parsear los argumentos de la línea de comandos
|
||||
args = parse_arguments()
|
||||
# Cargar y analizar el fichero .dat
|
||||
file = load_dat_file(dat_path=args.dat)
|
||||
|
||||
# Manejar la opción de listar desarrolladores o juegos
|
||||
if args.list:
|
||||
if args.manufacturer:
|
||||
list_games_by_manufacturer(file=file, manufacturer=args.manufacturer)
|
||||
else:
|
||||
list_manufacturers(file=file)
|
||||
|
||||
# Manejar la opción de copiar roms
|
||||
if args.copy:
|
||||
if args.manufacturer:
|
||||
copy_games(file=file, args=args, all_games=False)
|
||||
else:
|
||||
copy_games(file=file, args=args, all_games=True)
|
||||
|
||||
# Manejar la opción de búsqueda de juegos
|
||||
if args.find:
|
||||
find_games(file=file, search_string=args.find)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user