Afegit: media_mover.py

Retocat: fbneo_roms_by_manufacturer.py
This commit is contained in:
2025-01-12 20:28:52 +01:00
parent 9400205773
commit 70db46d4f2
8 changed files with 173541 additions and 257 deletions
+2 -1
View File
@@ -1,2 +1,3 @@
.DS_Store
settings.json
settings.json
__pycache__
-256
View File
@@ -1,256 +0,0 @@
# 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
from xml.dom import minidom
# Elimina los caracteres ilegales de la cadena de texto
def normalize_path(path):
illegal_chars = ["<", ">", ":", '"', "/", "\\", "|", "?", "*"]
replace_with = "_"
for char in illegal_chars:
path = path.replace(char, replace_with)
return path
# Inicialización de las opciones
ignore_list = ["DECO Cassette", "Bootleg", "prototype", "Quiz", "Mahjong", "Demo"]
ignore_system = ["neogeo"]
# Obtiene los argumentos
parser = argparse.ArgumentParser(
description="Gestiona las roms de fbneo por desarrolladores a partir de un fichero .dat"
)
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")
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="")
args = parser.parse_args()
# Importa el xml
if args.dat == None:
print("No se ha especificado un fichero .dat")
sys.exit(2)
if not os.path.isfile(args.dat):
print("No se encuentra el fichero .dat")
sys.exit(2)
print("Parsing {} file".format(args.dat))
file = minidom.parse(args.dat)
# Lista los desarrolladores
if args.list and args.manufacturer == None:
print("List of all manufacturers:")
manufacturers = []
games = file.getElementsByTagName("game")
for game in games:
manufacturer = game.getElementsByTagName("manufacturer")[0]
manufacturers.append(manufacturer.firstChild.data)
# Elimina los duplicados
manufacturers = list(dict.fromkeys(manufacturers))
# Ordena la lista
manufacturers.sort()
# Imprime la lista
for i in manufacturers:
print(i)
# Lista los juegos de un desarrollador
if args.list and args.manufacturer != None:
games = file.getElementsByTagName("game")
print("List of all", args.manufacturer, "games:", len(games))
for game in games:
cloneof = game.getAttribute("cloneof")
isbios = game.getAttribute("isbios")
manufacturer = game.getElementsByTagName("manufacturer")[0]
description = game.getElementsByTagName("description")[0]
if (
(manufacturer.firstChild.data == args.manufacturer
or args.manufacturer == 'all')
and not cloneof
and not isbios
):
print(description.firstChild.data, '==>', game.getAttribute("name") + ".zip from", manufacturer.firstChild.data)
# Copia los juegos del desarrollador seleccionado
if (
args.copy
and os.path.isdir(args.input)
and os.path.isdir(args.output)
and args.manufacturer != None
):
# Comprueba si ha de crear la carpeta con el nombre del desarrollador
if args.create_folder:
normalized_manufacturer = normalize_path(args.manufacturer)
os.mkdir(os.path.join(args.output, args.manufacturer))
notfound = []
ignored_games = []
copied_games = []
games = file.getElementsByTagName("game")
print("Copying all", args.manufacturer, "games:", 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 ""
)
if (
manufacturer.firstChild.data == args.manufacturer
and not cloneof
and not isbios
and status == "good"
):
for ignore_element in ignore_list:
if ignore_element.casefold() in description.firstChild.data.casefold():
ignored_games.append(description.firstChild.data)
isignored = True
for ignore_element in ignore_system:
if ignore_element.casefold() in romof.casefold():
ignored_games.append(description.firstChild.data)
isignored = True
if not isignored:
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:
dst = os.path.join(args.output, normalized_manufacturer, name)
else:
dst = os.path.join(args.output, name)
if os.path.isfile(src):
shutil.copyfile(src, dst)
copied_games.append(description.firstChild.data)
print(description.firstChild.data, '==>', game.getAttribute("name") + ".zip")
else:
notfound.append(description.firstChild.data)
print("\nMissing games:", len(notfound))
for game in notfound:
print(game)
print("\nIgnored games:", len(ignored_games))
for game in ignored_games:
print(game)
print("\nCopied games: ", len(copied_games))
print("Missing games:", len(notfound))
print("Ignored games:", len(ignored_games))
# Copia todos los juegos
if (
args.copy
and os.path.isdir(args.input)
and os.path.isdir(args.output)
and args.manufacturer == None
):
notfound = []
ignored_games = []
copied_games = []
games = file.getElementsByTagName("game")
print("Copying all games:", 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 ""
)
if not cloneof and not isbios and status == "good":
for ignore_element in ignore_list:
if ignore_element.casefold() in description.firstChild.data.casefold():
ignored_games.append(description.firstChild.data)
isignored = True
for ignore_element in ignore_system:
if ignore_element.casefold() in romof.casefold():
ignored_games.append(description.firstChild.data)
isignored = True
if not isignored:
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:
dst = os.path.join(args.output, name)
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)
print("\nMissing games:", len(notfound))
for game in notfound:
print(game)
print("\nIgnored games:", len(ignored_games))
for game in ignored_games:
print(game)
print("\nCopied games: ", len(copied_games))
print("Missing games:", len(notfound))
print("Ignored games:", len(ignored_games))
File diff suppressed because it is too large Load Diff
+12
View File
@@ -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()
+246
View File
@@ -0,0 +1,246 @@
ROM_FOLDERS = [
{"frontend": "batocera", "path": "/home/sergio/roms/batocera_arrm_scrapped"},
{"frontend": "es-de", "path": "/home/sergio/roms/ES-DE/ROMs"},
]
CONFIG_FOLDERS = [
{"frontend": "batocera", "path": "downloaded_images"},
{"frontend": "es-de", "path": "/home/sergio/roms/ES-DE/CONFIG"},
]
SYSTEMS = [
{"name": "3DO Interactive Multiplayer", "batocera": "3do", "es-de": "3do"},
{"name": "Coleco Adam", "batocera": "", "es-de": "adam"},
{"name": "Adventure Game Studio Game Engine", "batocera": "", "es-de": "ags"},
{"name": "Commodore Amiga", "batocera": "", "es-de": "amiga"},
{"name": "Commodore Amiga 1200", "batocera": "", "es-de": "amiga1200"},
{"name": "Commodore Amiga 600", "batocera": "", "es-de": "amiga600"},
{"name": "Commodore Amiga CD32", "batocera": "", "es-de": "amigacd32"},
{"name": "Amstrad CPC", "batocera": "", "es-de": "amstradcpc"},
{"name": "Google Android", "batocera": "", "es-de": "android"},
{"name": "Apple II", "batocera": "", "es-de": "apple2"},
{"name": "Apple IIGS", "batocera": "", "es-de": "apple2gs"},
{"name": "Arcade", "batocera": "", "es-de": "arcade"},
{"name": "Emerson Arcadia 2001", "batocera": "", "es-de": "arcadia"},
{"name": "Acorn Archimedes", "batocera": "", "es-de": "archimedes"},
{"name": "Arduboy Miniature Game System", "batocera": "", "es-de": "arduboy"},
{"name": "Bally Astrocade", "batocera": "", "es-de": "astrocde"},
{"name": "Atari 2600", "batocera": "atari2600", "es-de": "atari2600"},
{"name": "Atari 5200", "batocera": "atari5200", "es-de": "atari5200"},
{"name": "Atari 7800 ProSystem", "batocera": "atari7800", "es-de": "atari7800"},
{"name": "Atari 800", "batocera": "", "es-de": "atari800"},
{"name": "Atari Jaguar", "batocera": "", "es-de": "atarijaguar"},
{"name": "Atari Jaguar CD", "batocera": "", "es-de": "atarijaguarcd"},
{"name": "Atari Lynx", "batocera": "lynx", "es-de": "atarilynx"},
{"name": "Atari ST", "batocera": "", "es-de": "atarist"},
{"name": "Atari XE", "batocera": "", "es-de": "atarixe"},
{"name": "Sammy Corporation Atomiswave", "batocera": "", "es-de": "atomiswave"},
{"name": "Acorn Computers BBC Micro", "batocera": "", "es-de": "bbcmicro"},
{"name": "Commodore 64", "batocera": "", "es-de": "c64"},
{"name": "Philips CD-i", "batocera": "", "es-de": "cdimono1"},
{"name": "Commodore CDTV", "batocera": "", "es-de": "cdtv"},
{"name": "ChaiLove Game Engine", "batocera": "", "es-de": "chailove"},
{"name": "Fairchild Channel F", "batocera": "", "es-de": "channelf"},
{"name": "Tandy Color Computer", "batocera": "", "es-de": "coco"},
{"name": "Coleco ColecoVision", "batocera": "", "es-de": "colecovision"},
{"name": "Console Arcade Systems", "batocera": "", "es-de": "consolearcade"},
{"name": "Capcom Play System", "batocera": "", "es-de": "cps"},
{"name": "Capcom Play System I", "batocera": "", "es-de": "cps1"},
{"name": "Capcom Play System II", "batocera": "", "es-de": "cps2"},
{"name": "Capcom Play System III", "batocera": "", "es-de": "cps3"},
{"name": "VTech CreatiVision", "batocera": "", "es-de": "crvision"},
{
"name": "Daphne Arcade LaserDisc Emulator",
"batocera": "daphne",
"es-de": "daphne",
},
{"name": "Desktop Applications", "batocera": "", "es-de": "desktop"},
{"name": "Doom", "batocera": "", "es-de": "doom"},
{"name": "DOS (PC)", "batocera": "", "es-de": "dos"},
{"name": "Dragon Data Dragon 32", "batocera": "", "es-de": "dragon32"},
{"name": "Sega Dreamcast", "batocera": "dreamcast", "es-de": "dreamcast"},
{"name": "EasyRPG Game Engine", "batocera": "", "es-de": "easyrpg"},
{"name": "Acorn Electron", "batocera": "", "es-de": "electron"},
{"name": "Emulators", "batocera": "", "es-de": "emulators"},
{"name": "Epic Games Store", "batocera": "", "es-de": "epic"},
{"name": "Nintendo Family Computer", "batocera": "", "es-de": "famicom"},
{"name": "FinalBurn Alpha", "batocera": "", "es-de": "fba"},
{"name": "FinalBurn Neo", "batocera": "fbneo", "es-de": "fbneo"},
{"name": "Nintendo Famicom Disk System", "batocera": "", "es-de": "fds"},
{"name": "Adobe Flash", "batocera": "", "es-de": "flash"},
{"name": "Fujitsu FM-7", "batocera": "", "es-de": "fm7"},
{"name": "Fujitsu FM Towns", "batocera": "", "es-de": "fmtowns"},
{"name": "Future Pinball", "batocera": "", "es-de": "fpinball"},
{"name": "Bit Corporation Gamate", "batocera": "", "es-de": "gamate"},
{"name": "Nintendo Game and Watch", "batocera": "", "es-de": "gameandwatch"},
{"name": "Tiger Electronics Game.com", "batocera": "", "es-de": "gamecom"},
{"name": "Sega Game Gear", "batocera": "gamegear", "es-de": "gamegear"},
{"name": "Nintendo Game Boy", "batocera": "gb", "es-de": "gb"},
{"name": "Nintendo Game Boy Advance", "batocera": "gba", "es-de": "gba"},
{"name": "Nintendo Game Boy Color", "batocera": "gbc", "es-de": "gbc"},
{"name": "Nintendo GameCube", "batocera": "", "es-de": "gc"},
{"name": "Sega Genesis", "batocera": "", "es-de": "genesis"},
{"name": "Hartung Game Master", "batocera": "", "es-de": "gmaster"},
{"name": "Amstrad GX4000", "batocera": "", "es-de": "gx4000"},
{
"name": "Mattel Electronics Intellivision",
"batocera": "",
"es-de": "intellivision",
},
{"name": "Java 2 Micro Edition (J2ME)", "batocera": "", "es-de": "j2me"},
{"name": "Kodi Home Theatre Software", "batocera": "", "es-de": "kodi"},
{"name": "LaserDisc Games", "batocera": "", "es-de": "laserdisc"},
{"name": "LCD Handheld Games", "batocera": "", "es-de": "lcdgames"},
{"name": "LowRes NX Fantasy Console", "batocera": "", "es-de": "lowresnx"},
{"name": "Lutro Game Engine", "batocera": "", "es-de": "lutro"},
{"name": "Apple Macintosh", "batocera": "", "es-de": "macintosh"},
{"name": "Multiple Arcade Machine Emulator", "batocera": "mame", "es-de": "mame"},
{"name": "AdvanceMAME", "batocera": "", "es-de": "mame-advmame"},
{"name": "Sega Master System", "batocera": "", "es-de": "mastersystem"},
{"name": "Sega Mega-CD", "batocera": "", "es-de": "megacd"},
{"name": "Sega Mega-CD", "batocera": "", "es-de": "megacdjp"},
{"name": "Sega Mega Drive", "batocera": "megadrive", "es-de": "megadrive"},
{"name": "Sega Mega Drive", "batocera": "", "es-de": "megadrivejp"},
{"name": "Creatronic Mega Duck", "batocera": "", "es-de": "megaduck"},
{"name": "Multi Emulator Super System", "batocera": "", "es-de": "mess"},
{"name": "Sega Model 2", "batocera": "model2", "es-de": "model2"},
{"name": "Sega Model 3", "batocera": "model3", "es-de": "model3"},
{"name": "Thomson MO/TO Series", "batocera": "", "es-de": "moto"},
{"name": "MSX", "batocera": "", "es-de": "msx"},
{"name": "MSX1", "batocera": "", "es-de": "msx1"},
{"name": "MSX2", "batocera": "", "es-de": "msx2"},
{"name": "MSX Turbo R", "batocera": "", "es-de": "msxturbor"},
{"name": "M.U.G.E.N Game Engine", "batocera": "", "es-de": "mugen"},
{"name": "Othello Multivision", "batocera": "", "es-de": "multivision"},
{"name": "Nintendo 3DS", "batocera": "", "es-de": "n3ds"},
{"name": "Nintendo 64", "batocera": "n64", "es-de": "n64"},
{"name": "Nintendo 64DD", "batocera": "", "es-de": "n64dd"},
{"name": "Sega NAOMI", "batocera": "naomi", "es-de": "naomi"},
{"name": "Sega NAOMI 2", "batocera": "naomi2", "es-de": "naomi2"},
{"name": "Sega NAOMI GD-ROM", "batocera": "", "es-de": "naomigd"},
{"name": "Nintendo DS", "batocera": "", "es-de": "nds"},
{"name": "SNK Neo Geo", "batocera": "neogeo", "es-de": "neogeo"},
{"name": "SNK Neo Geo CD", "batocera": "neogeocd", "es-de": "neogeocd"},
{"name": "SNK Neo Geo CD", "batocera": "", "es-de": "neogeocdjp"},
{"name": "Nintendo Entertainment System", "batocera": "nes", "es-de": "nes"},
{"name": "Nokia N-Gage", "batocera": "", "es-de": "ngage"},
{"name": "SNK Neo Geo Pocket", "batocera": "ngp", "es-de": "ngp"},
{"name": "SNK Neo Geo Pocket Color", "batocera": "ngpc", "es-de": "ngpc"},
{"name": "Magnavox Odyssey 2", "batocera": "", "es-de": "odyssey2"},
{"name": "OpenBOR Game Engine", "batocera": "", "es-de": "openbor"},
{"name": "Tangerine Computer Systems Oric", "batocera": "", "es-de": "oric"},
{"name": "Palm OS", "batocera": "", "es-de": "palm"},
{"name": "IBM PC", "batocera": "", "es-de": "pc"},
{"name": "NEC PC-8800 Series", "batocera": "", "es-de": "pc88"},
{"name": "NEC PC-9800 Series", "batocera": "", "es-de": "pc98"},
{"name": "PC Arcade Systems", "batocera": "", "es-de": "pcarcade"},
{"name": "NEC PC Engine", "batocera": "pcengine", "es-de": "pcengine"},
{"name": "NEC PC Engine CD", "batocera": "pcenginecd", "es-de": "pcenginecd"},
{"name": "NEC PC-FX", "batocera": "", "es-de": "pcfx"},
{"name": "PICO-8 Fantasy Console", "batocera": "", "es-de": "pico8"},
{"name": "Commodore Plus/4", "batocera": "", "es-de": "plus4"},
{"name": "Nintendo Pokémon Mini", "batocera": "", "es-de": "pokemini"},
{"name": "Ports", "batocera": "", "es-de": "ports"},
{"name": "Sony PlayStation 2", "batocera": "", "es-de": "ps2"},
{"name": "Sony PlayStation 3", "batocera": "", "es-de": "ps3"},
{"name": "Sony PlayStation Portable", "batocera": "psp", "es-de": "psp"},
{"name": "Sony PlayStation Vita", "batocera": "", "es-de": "psvita"},
{"name": "Sony PlayStation", "batocera": "psx", "es-de": "psx"},
{"name": "Casio PV-1000", "batocera": "", "es-de": "pv1000"},
{"name": "Quake", "batocera": "", "es-de": "quake"},
{"name": "MGT SAM Coupé", "batocera": "", "es-de": "samcoupe"},
{"name": "Nintendo Satellaview", "batocera": "", "es-de": "satellaview"},
{"name": "Sega Saturn", "batocera": "saturn", "es-de": "saturn"},
{"name": "Sega Saturn", "batocera": "", "es-de": "saturnjp"},
{"name": "ScummVM Game Engine", "batocera": "", "es-de": "scummvm"},
{"name": "Epoch Super Cassette Vision", "batocera": "", "es-de": "scv"},
{"name": "Sega Mega Drive 32X", "batocera": "sega32x", "es-de": "sega32x"},
{"name": "Sega Super 32X", "batocera": "", "es-de": "sega32xjp"},
{"name": "Sega Genesis 32X", "batocera": "", "es-de": "sega32xna"},
{"name": "Sega CD", "batocera": "segacd", "es-de": "segacd"},
{"name": "Nintendo SFC (Super Famicom)", "batocera": "", "es-de": "sfc"},
{"name": "Sega SG-1000", "batocera": "sg1000", "es-de": "sg-1000"},
{"name": "Nintendo Super Game Boy", "batocera": "", "es-de": "sgb"},
{"name": "Nintendo SNES (Super Nintendo)", "batocera": "snes", "es-de": "snes"},
{"name": "Nintendo SNES (Super Nintendo)", "batocera": "", "es-de": "snesna"},
{"name": "Solarus Game Engine", "batocera": "", "es-de": "solarus"},
{"name": "Spectravideo", "batocera": "", "es-de": "spectravideo"},
{"name": "Valve Steam", "batocera": "", "es-de": "steam"},
{"name": "Sega Titan Video Game System", "batocera": "", "es-de": "stv"},
{"name": "Bandai SuFami Turbo", "batocera": "", "es-de": "sufami"},
{"name": "NEC SuperGrafx", "batocera": "", "es-de": "supergrafx"},
{"name": "Watara Supervision", "batocera": "", "es-de": "supervision"},
{"name": "Funtech Super A'Can", "batocera": "", "es-de": "supracan"},
{"name": "Nintendo Switch", "batocera": "", "es-de": "switch"},
{"name": "Symbian", "batocera": "", "es-de": "symbian"},
{"name": "Tano Dragon", "batocera": "", "es-de": "tanodragon"},
{"name": "NEC TurboGrafx-CD", "batocera": "", "es-de": "tg-cd"},
{"name": "NEC TurboGrafx-16", "batocera": "", "es-de": "tg16"},
{"name": "Texas Instruments TI-99", "batocera": "", "es-de": "ti99"},
{"name": "TIC-80 Fantasy Computer", "batocera": "", "es-de": "tic80"},
{"name": "Thomson TO8", "batocera": "", "es-de": "to8"},
{"name": "Namco-Sega-Nintendo Triforce", "batocera": "", "es-de": "triforce"},
{"name": "Tandy TRS-80", "batocera": "", "es-de": "trs-80"},
{"name": "Taito Type X", "batocera": "", "es-de": "type-x"},
{"name": "Uzebox Open Source Console", "batocera": "", "es-de": "uzebox"},
{"name": "GCE Vectrex", "batocera": "", "es-de": "vectrex"},
{"name": "Commodore VIC-20", "batocera": "", "es-de": "vic20"},
{"name": "Philips Videopac G7000", "batocera": "", "es-de": "videopac"},
{"name": "Nintendo Virtual Boy", "batocera": "", "es-de": "virtualboy"},
{"name": "Visual Pinball", "batocera": "", "es-de": "vpinball"},
{"name": "VTech V.Smile", "batocera": "", "es-de": "vsmile"},
{"name": "WASM-4 Fantasy Console", "batocera": "", "es-de": "wasm4"},
{"name": "Nintendo Wii", "batocera": "", "es-de": "wii"},
{"name": "Nintendo Wii U", "batocera": "", "es-de": "wiiu"},
{"name": "Microsoft Windows", "batocera": "", "es-de": "windows"},
{"name": "Microsoft Windows 3.x", "batocera": "", "es-de": "windows3x"},
{"name": "Microsoft Windows 9x", "batocera": "", "es-de": "windows9x"},
{"name": "Bandai WonderSwan", "batocera": "wswan", "es-de": "wonderswan"},
{
"name": "Bandai WonderSwan Color",
"batocera": "wswanc",
"es-de": "wonderswancolor",
},
{"name": "Sharp X1", "batocera": "", "es-de": "x1"},
{"name": "Sharp X68000", "batocera": "", "es-de": "x68000"},
{"name": "Microsoft Xbox", "batocera": "", "es-de": "xbox"},
{"name": "Microsoft Xbox 360", "batocera": "", "es-de": "xbox360"},
{"name": "Infocom Z-machine", "batocera": "", "es-de": "zmachine"},
{"name": "Sinclair ZX81", "batocera": "", "es-de": "zx81"},
{"name": "Sinclair ZX Spectrum Next", "batocera": "", "es-de": "zxnext"},
{"name": "Sinclair ZX Spectrum", "batocera": "", "es-de": "zxspectrum"},
]
ES_DE_MEDIA = [
"3dboxes",
"backcovers",
"covers",
"fanart",
"manuals",
"marquees",
"miximages",
"physicalmedia",
"screenshots",
"titlescreens",
"videos",
]
BATOCERA_MEDIA = [
"boxart",
"cartridge",
"image",
"marquee",
"mix",
"screenshot",
"video",
"wheel",
]
RELACION = [
{"batocera": "-boxart.", "es-de": "covers"},
{"batocera": "-cartridge.", "es-de": "physicalmedia"},
{"batocera": "-marquee.", "es-de": "marquees"},
{"batocera": "-mix.", "es-de": "miximages"},
{"batocera": "-screenshot.", "es-de": "screenshots"},
{"batocera": "-video.", "es-de": "videos"},
]
+89
View File
@@ -0,0 +1,89 @@
from config import ROM_FOLDERS, CONFIG_FOLDERS, SYSTEMS, ES_DE_MEDIA, BATOCERA_MEDIA, RELACION
import os
import shutil
import time
def getRomPath(frontend):
for folder in ROM_FOLDERS:
if folder["frontend"] == frontend:
return folder["path"]
return None
def getConfigPath(frontend):
for folder in CONFIG_FOLDERS:
if folder["frontend"] == frontend:
return folder["path"]
return None
def getSystemShortName(name, frontend):
for system in SYSTEMS:
if system["name"].lower() == name.lower():
return system[frontend]
return None
def verificar_sistemas_y_carpetas(sistemas, carpetas):
resultados = []
for sistema in sistemas:
if sistema["batocera"] and sistema["es-de"]:
carpetas_existentes = True
for carpeta in carpetas:
ruta = os.path.join(carpeta["path"], sistema[carpeta["frontend"]])
if not os.path.isdir(ruta):
carpetas_existentes = False
break
resultados.append((sistema["name"], carpetas_existentes))
return resultados
def copiar_archivos(origen, destino):
try:
# Crear la carpeta de destino si no existe
if not os.path.exists(origen):
return
if not os.path.exists(destino):
os.makedirs(destino)
# Copiar todos los archivos
for archivo in os.listdir(origen):
#print(archivo)
ruta_origen = os.path.join(origen, archivo)
if os.path.isfile(ruta_origen):
for relacion in RELACION:
if relacion["batocera"] in archivo:
final_file = archivo.replace(relacion["batocera"][:-1], "")
destino_carpeta = os.path.join(destino, relacion["es-de"])
if not os.path.exists(destino_carpeta):
os.makedirs(destino_carpeta)
ruta_destino = os.path.join(destino_carpeta, final_file)
if not os.path.exists(ruta_destino):
shutil.copy2(ruta_origen, ruta_destino)
print(f"Archivo {archivo} copiado a {ruta_destino}")
break
except Exception as e:
print(f"Error al copiar archivos: {e}")
def copy_media(system):
batocera_short_name = getSystemShortName(system, "batocera")
es_de_short_name = getSystemShortName(system, "es-de")
origen = os.path.join(getRomPath("batocera"), batocera_short_name, getConfigPath("batocera"))
destino = os.path.join(getConfigPath("es-de"), "downloaded_media", es_de_short_name)
#print(origen)
#print(destino)
copiar_archivos(origen, destino)
def main():
# Ejecutar y mostrar resultados
resultados = verificar_sistemas_y_carpetas(SYSTEMS, ROM_FOLDERS)
#resultados = [("ATARI LYNX", True)]
for sistema, existe in resultados:
if existe:
print(f"\nCopiando medios del sistema: {sistema.upper()}")
time.sleep(2)
copy_media(sistema)
if __name__ == "__main__":
main()
View File