Files
scrapped-media-mover/scrapped_media_mover.py
2025-04-11 07:32:31 +02:00

276 lines
10 KiB
Python

from systems_definitions import get_system_name, filter_translatable_systems
from media_definitions import media_table, get_media_name
from config import SOURCE_FOLDER, DEST_FOLDER, GET_VIDEOS, SYSTEMS, CREATE_SYM_LINKS
import os
import shutil
def list_directories(path):
"""
Devuelve una lista de directorios en la ruta especificada.
Si SYSTEMS no está vacío, filtra por directorios que estén en SYSTEMS.
"""
if not SYSTEMS: # Si SYSTEMS está vacío, devolver todos los directorios
directories = [
name for name in os.listdir(path)
if os.path.isdir(os.path.join(path, name))
]
else:
directories = [
name for name in os.listdir(path)
if os.path.isdir(os.path.join(path, name)) and name in SYSTEMS
]
return directories
def list_files(path):
"""Devuelve una lista de ficheros (no directorios) en la ruta especificada, excluyendo archivos *.xml."""
files = [
name for name in os.listdir(path)
if os.path.isfile(os.path.join(path, name)) and not name.endswith(".xml")
]
return files
def directory_exists(path):
"""Comprueba si un directorio existe."""
return os.path.isdir(path)
def get_file_name_without_extension(file_path):
"""Devuelve el nombre del fichero sin su extensión."""
file_name, _ = os.path.splitext(os.path.basename(file_path))
return file_name
def find_file_extension(folder, base_name):
"""Busca un archivo que coincida con el nombre base y el sufijo, y devuelve solo la extensión."""
for file in os.listdir(folder):
if file.startswith(base_name):
_, extension = os.path.splitext(file) # Obtiene la extensión del archivo
return extension # Devuelve solo la extensión
return None
def create_file_list():
"""
Crea una lista de archivos basándose en los sistemas translatables
y las carpetas de origen y destino especificadas.
Procesa cada sistema en la lista filtrada:
- Verifica la existencia de la carpeta "downloaded_images".
- Agrega los archivos (ROMs) de cada sistema, excluyendo los archivos .xml.
- Gestiona las ROMs y crea un diccionario de medios asociado a cada archivo.
- Agrega el archivo "gamelist.xml" si está presente en el sistema.
Retorna:
list: Una lista de diccionarios, donde cada diccionario representa
un archivo ROM o un gamelist, incluyendo información de origen y destino.
Nota:
Usa funciones auxiliares como `filter_translatable_systems`,
`list_directories`, `directory_exists`, `list_files`,
`get_file_name_without_extension`, `find_file_extension` y otras.
Ejemplo de entrada:
- SOURCE_FOLDER: Carpeta donde se encuentran los sistemas originales.
- DEST_FOLDER: Carpeta donde se copiarán las ROMs y medios.
- media_table: Diccionario con las configuraciones de medios.
Ejemplo de salida:
[
{
"name": "rom_name",
"rom_source": "ruta/origen/rom",
"rom_dest": "ruta/destino/rom",
"media": {
"key_source": "ruta/origen/medio",
"key_dest": "ruta/destino/medio"
}
},
{
"name": "gamelist",
"rom_source": "ruta/origen/gamelist.xml",
"rom_dest": "ruta/destino/gamelist.xml"
}
]
"""
system_list = filter_translatable_systems(list_directories(SOURCE_FOLDER))
file_list = []
for system in system_list:
folder = os.path.join(SOURCE_FOLDER, system)
# Saltar sistemas sin la carpeta "downloaded_images"
if not directory_exists(os.path.join(folder, "downloaded_images")):
continue
# Añade las roms de la carpeta excluyendo ficheros .xml
roms = list_files(folder)
# Gestiona la lista de roms
for rom in roms:
rom_name = get_file_name_without_extension(rom)
element = {}
# Configuración básica del rom
element["name"] = rom_name
element["rom_source"] = os.path.join(folder, rom)
element["rom_dest"] = os.path.join(DEST_FOLDER, "ROMs", get_system_name(system), rom)
# Crear el diccionario "media" con dos claves por entrada
media_dict = {}
for key in media_table.keys():
base_folder = os.path.join(folder, "downloaded_images")
base_name = f"{rom_name}-{key}"
# Llamar a la función para obtener la extensión
extension = find_file_extension(base_folder, base_name)
# Verificar si se encontró la extensión
if extension:
media_dict[f"{key}_source"] = os.path.join(base_folder, base_name + extension)
media_dict[f"{key}_dest"] = os.path.join(DEST_FOLDER, "ES-DE", "downloaded_media", get_system_name(system), media_table[key], rom_name + extension)
# Asignar el diccionario "media" al elemento
element["media"] = media_dict
# Añadir el elemento a la lista de ficheros
file_list.append(element)
print(system + " - " + rom_name)
# Gestiona el fichero "gamelist.xml"
file_name = "gamelist.xml"
gamelist = os.path.join(folder, file_name)
if os.path.isfile(gamelist):
element = {}
element["name"] = "gamelist"
element["rom_source"] = os.path.join(folder, file_name)
element["rom_dest"] = os.path.join(DEST_FOLDER, "ES-DE", "gamelists", get_system_name(system), file_name)
file_list.append(element)
return file_list
def copy_file(source_path, dest_path):
"""
Copia un archivo desde source_path a dest_path, o crea un enlace simbólico
según el valor de CREATE_SYM_LINKS.
Si el archivo de destino ya existe, no hace nada.
Si el archivo tiene una extensión no permitida, no lo copia ni lo enlaza.
Si el archivo es un .xml, se usa un método especial para copiarlo.
"""
# Lista de extensiones no permitidas
forbidden_extensions = []
if not GET_VIDEOS:
forbidden_extensions.append(".mp4")
if not source_path or not dest_path:
print(f"Source o destino inválido: {source_path}, {dest_path}. Saltando...")
return
# Verificar si el archivo tiene una extensión no permitida
_, extension = os.path.splitext(source_path)
if extension in forbidden_extensions:
print(f"Archivo con extensión no permitida ({extension}): {source_path}. Saltando...")
return
# Manejo especial para archivos .xml
if extension == ".xml":
copy_xml_file(source_path, dest_path) # Llamar al método especial para XML
return
# Crear el directorio de destino si no existe
dest_dir = os.path.dirname(dest_path)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
print(f"Directorio creado: {dest_dir}")
# Verificar si el archivo de destino ya existe
if os.path.exists(dest_path):
print(f"El archivo ya existe: {dest_path}. No se realiza la operación.")
return
# Comportamiento según CREATE_SYM_LINKS
try:
if CREATE_SYM_LINKS:
os.symlink(source_path, dest_path) # Crear el enlace simbólico
print(f"Enlace simbólico creado: {source_path} -> {dest_path}")
else:
shutil.copy2(source_path, dest_path) # Copiar el archivo
print(f"Copiado: {source_path} -> {dest_path}")
except FileNotFoundError:
print(f"Archivo fuente no encontrado: {source_path}. Saltando...")
except Exception as e:
print(f"Error al realizar la operación con {source_path} a {dest_path}: {e}")
def copy_xml_file(source_path, dest_path):
"""
Copia un archivo XML omitiendo las líneas que contienen ciertos textos no deseados.
"""
# Lista de textos a omitir
texts_to_omit = [
"<boxart>",
"<boxback>",
"<cartridge>",
"<image>",
"<manual>",
"<marquee>",
"<mix>",
"<screenshot>",
"<thumbnail />",
"<video>",
"<wheel>",
]
# Crear el directorio de destino si no existe
dest_dir = os.path.dirname(dest_path)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
print(f"Directorio creado: {dest_dir}")
try:
# Leer el archivo fuente y escribir solo las líneas permitidas en el archivo destino
with open(source_path, "r", encoding="utf-8") as source_file, open(dest_path, "w", encoding="utf-8") as dest_file:
for line in source_file:
# Si ninguna de las etiquetas a omitir está en la línea, escríbela en el destino
if not any(text in line for text in texts_to_omit):
dest_file.write(line)
print(f"Archivo XML procesado y copiado: {source_path} -> {dest_path}")
except FileNotFoundError:
print(f"Archivo XML fuente no encontrado: {source_path}. Saltando...")
except Exception as e:
print(f"Error al procesar el archivo XML {source_path} a {dest_path}: {e}")
def copy_files_with_structure(data):
"""
Copia los archivos apuntados por las claves *_source a sus homólogos *_dest.
Incluye rom_source y rom_dest. Crea las carpetas de destino si no existen.
"""
# Manejar archivos de media (claves *_source y *_dest)
if "media" in data:
for key, source_path in data["media"].items():
if key.endswith("_source"):
# Buscar la clave _dest correspondiente
dest_key = key.replace("_source", "_dest")
dest_path = data["media"].get(dest_key)
copy_file(source_path, dest_path)
# Manejar archivo de rom_source -> rom_dest
if "rom_source" in data and "rom_dest" in data:
copy_file(data["rom_source"], data["rom_dest"])
def main():
"""Función principal del programa."""
file_list = create_file_list()
for game in file_list:
copy_files_with_structure(game)
# Verifica si este archivo se ejecuta como script principal
if __name__ == "__main__":
main()