diff --git a/queries.sql b/queries.sql index 319f104..da930c4 100644 --- a/queries.sql +++ b/queries.sql @@ -130,5 +130,49 @@ WHERE g.text like '%Game:%' AND g.text not like 'Casual%' ) +ORDER BY + e.title; + +-- Consulta 3: ZXNEXT - Devuelve juegos y solo archivos de cinta o pokes +SELECT DISTINCT + e.title, + l.name, + r.release_year, + d.file_link, + f.text +FROM + ( + ( + ( + ( + ( + ( + publishers p + INNER JOIN entries e ON p.entry_id = e.id + ) INNER JOIN labels l ON p.label_id = l.id + ) INNER JOIN genretypes g ON e.genretype_id = g.id + ) INNER JOIN downloads d ON e.id = d.entry_id + ) INNER JOIN filetypes f ON d.filetype_id = f.id + ) INNER JOIN releases r ON e.id = r.entry_id + AND p.release_seq = r.release_seq + ) +WHERE + ( + e.availabletype_id = 'A' + OR e.availabletype_id = 'D' + ) + AND ( + f.text IN ( + 'Tape image', + 'Snapshot image', + 'POK pokes file' + ) + ) + AND r.release_seq = 0 + AND l.name like 'ZOSYA%' + AND ( + g.text like '%Game:%' + AND g.text not like 'Casual%' + ) ORDER BY e.title; \ No newline at end of file diff --git a/zxdb.py b/zxdb.py index 386d548..ac0c93b 100644 --- a/zxdb.py +++ b/zxdb.py @@ -47,19 +47,26 @@ temp_file = os.getenv('TEMP_FILE') # Parametros de configuración -should_clear_destination_path = True # Establece si se limpia primero la carpeta de destino -wait = True # Establece una pausa aleatoria entre descargas -min_wait = 2 # Segundos mínimos a esperar entre descargas -max_wait = 4 # Segundos máximos a esperar entre descargas -elements = [] +should_clear_destination_path = os.getenv('SHOULD_CLEAR_DESTINATION_PATH') == 'True' # Establece si se limpia primero la carpeta de destino +should_split_modern_and_classic = os.getenv('SHOULD_SPLIT_MODERN_AND_CLASSIC') == 'True'# Separa los juegos en dos carpetas a partir de un año especificado +should_sort_by_letter = os.getenv('SHOULD_SORT_BY_LETTER') == 'True' # Separa los juegos por carpetas en función de su primera letra +wait = os.getenv('WAIT') == 'True' # Establece una pausa aleatoria entre descargas +min_wait = int(os.getenv('MIN_WAIT')) # Cantidad de segundos mínima a esperar entre descargas +max_wait = int(os.getenv('MAX_WAIT')) # Cantidad de segundos máxima a esperar entre descargas +last_classic_year = int(os.getenv('LAST_CLASSIC_YEAR'))# Año usado para la separación entre juegos clásicos y modernos + +# Tipos de fichero que se guardan en la carpeta raíz del juego filetypes_on_root = [ "Tape image", "Disk image", "Snapshot image", "POK pokes file", -] # Tipos de fichero que se guardan en la carpeta raíz del juego +] +# Resto de variables globales +elements = [] +# Carga un fichero con consultas SQL def load_queries(file_path): with open(file_path, 'r') as file: queries = file.read().split(';') @@ -198,12 +205,30 @@ def print_status(current_file, total_files, element, total_files_width, status=" ) ) +# Compone la carpeta de destino en función de varios parámetros +def get_final_destination_folder(year, root_folder): + # Prefijo basado en el año + prefix1 = "" + if should_split_modern_and_classic: + if year == "none" or year is None or year > last_classic_year: + prefix1 = "modern" + else: + prefix1 = "classics" + + # Prefijo basado en la primera letra del nombre de la carpeta raíz + prefix2 = "" + if should_sort_by_letter: + if root_folder[0].isdigit(): + prefix2 = "0-9" + else: + prefix2 = root_folder[0].upper() + + # Combina los prefijos y la carpeta raíz para obtener la carpeta de destino final + return os.path.join(prefix1, prefix2, root_folder) + # Obtiene los ficheros de la consulta desde internet o desde la caché # y los deposita en la carpeta destino, descomprimiendo los archivos necesarios def get_files(): - # Configuración del logger - logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - # Variables para la presentación en pantalla de la descarga current_file = 0 total_files = len(elements) @@ -211,16 +236,8 @@ def get_files(): last_game_folder = "" for element in elements: - # Carpeta del juego en destino y en caché - release_year = element["release_year"] + classification_folder = get_final_destination_folder(element["release_year"], element["root_folder"]) - if release_year == "none" or release_year is None or release_year >= 1993: - classification_folder = "modern/" + element["root_folder"] - else: - classification_folder = "classics/" + element["root_folder"] - - - game_folder = element["root_folder"] destination_folder = os.path.join(destination_path, classification_folder) destination_subfolder = os.path.join(destination_folder, element["subfolder"]) cache_folder = os.path.join(cache_path, element["root_folder"]) @@ -233,9 +250,9 @@ def get_files(): # Actualiza las variables de presentación current_file += 1 - if game_folder != last_game_folder: - print("\n{}".format(game_folder)) - last_game_folder = game_folder + if element["root_folder"] != last_game_folder: + print("\n{}".format(element["root_folder"])) + last_game_folder = element["root_folder"] try: # Comprueba si ya existe el fichero a descargar @@ -286,21 +303,33 @@ def normalize_path(path): path = unidecode(path.replace(char, replace_with)) return path +# Elimina los subdirectorios vacios +def remove_empty_directories(path): + for root, dirs, files in os.walk(path, topdown=False): + for dir in dirs: + dir_path = os.path.join(root, dir) + try: + os.rmdir(dir_path) + logging.info(f"Directorio vacío eliminado: {dir_path}") + except OSError as e: + # El directorio no está vacío o ocurrió otro error + pass # Limpia la carpeta de destino def clear_destination_folder(): if should_clear_destination_path: - print("Clear destination folder ...") - folder = destination_path - for filename in os.listdir(folder): - file_path = os.path.join(folder, filename) + logging.info("Limpiando la carpeta de destino ...") + for filename in os.listdir(destination_path): + file_path = os.path.join(destination_path, filename) try: if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path) + logging.info(f"Archivo eliminado: {file_path}") elif os.path.isdir(file_path): shutil.rmtree(file_path) + logging.info(f"Directorio eliminado: {file_path}") except Exception as e: - print('Failed to delete %s. Reason: %s' % (file_path, e)) + logging.error(f'No se pudo eliminar {file_path}. Razón: {e}') # Imprime la lista de elementos def print_elements(mode=0): @@ -323,7 +352,7 @@ def print_elements(mode=0): # Bucle principal def main(): - connect(query_index=1) + connect(query_index=3) process_elements() print_elements(mode=1) clear_destination_folder()