afegit convertir-imagenes

This commit is contained in:
2026-02-19 10:31:53 +01:00
parent 18e22e167d
commit f4104ded96
5 changed files with 78 additions and 14 deletions
+4 -3
View File
@@ -41,16 +41,17 @@ Las operaciones que tocan el contenido del archivo piden confirmación por defec
|------|-------------|-------------------|
| `--limpiar` | Elimina ficheros basura (`thumbs.db`, `.ds_store`, `__MACOSX`, `desktop.ini`) y reempaqueta como CBZ. | Sí |
| `--convertir` | Convierte al formato indicado por `--formato` (por defecto CBZ). | No |
| `--estandarizar` | Equivale a `--limpiar` + `--convertir` en secuencia. | Solo para limpieza |
| `--estandarizar` | Equivale a `--limpiar` + `--renumerar` + `--uniformizar-imagenes` + `--convertir` en secuencia. | Sí, salvo para conversión de formato |
| `--renumerar` | Renombra las páginas a numeración secuencial con zero-padding (`001.jpg`, `002.jpg`…). | Sí |
| `--uniformizar-imagenes` | Convierte todas las imágenes al formato indicado por `--formato-imagen`. | Sí |
| `--uniformizar-imagenes` | Solo actúa si el archivo contiene imágenes en **formatos mixtos**. Si todas las imágenes ya son del mismo formato no hace nada, aunque no coincidan con `--formato-imagen`. | Sí |
| `--convertir-imagenes` | Convierte todas las imágenes que no sean `--formato-imagen`, independientemente de si los formatos ya son uniformes. | Sí |
### Opciones de formato
| Flag | Valores | Por defecto | Descripción |
|------|---------|-------------|-------------|
| `--formato` | `cbz`, `cbr` | `cbz` | Formato de archivo destino para `--convertir` y `--estandarizar`. |
| `--formato-imagen` | `jpg`, `png`, `webp` | `png` | Formato de imagen destino para `--uniformizar-imagenes`. |
| `--formato-imagen` | `jpg`, `png`, `webp` | `png` | Formato de imagen destino para `--uniformizar-imagenes` y `--convertir-imagenes`. |
| `--no-preguntar` | — | — | Desactiva la confirmación interactiva: aplica todas las operaciones automáticamente. |
---
+19 -7
View File
@@ -48,10 +48,22 @@ def extract_archive(path: str, dest_dir: str) -> str:
def repack_as_cbz(source_dir: str, target_path: str) -> None:
"""Empaqueta todos los archivos de source_dir en un CBZ (ZIP deflated)."""
with zipfile.ZipFile(target_path, "w", zipfile.ZIP_DEFLATED) as zf:
for root, _, files in os.walk(source_dir):
for f in files:
full = os.path.join(root, f)
rel = os.path.relpath(full, source_dir)
zf.write(full, rel)
"""Empaqueta todos los archivos de source_dir en un CBZ (ZIP deflated).
Escribe primero a un fichero temporal (.tmp) en el mismo directorio y
hace un os.replace() atómico al final, de modo que una interrupción
nunca deja un CBZ parcial ni destruye el original.
"""
tmp_path = target_path + ".tmp"
try:
with zipfile.ZipFile(tmp_path, "w", zipfile.ZIP_DEFLATED) as zf:
for root, _, files in os.walk(source_dir):
for f in files:
full = os.path.join(root, f)
rel = os.path.relpath(full, source_dir)
zf.write(full, rel)
os.replace(tmp_path, target_path)
except BaseException:
if os.path.exists(tmp_path):
os.remove(tmp_path)
raise
+23 -1
View File
@@ -17,7 +17,12 @@ from processors.checks import (
check_comicinfo,
)
from processors.page_normalizer import normalize_pages, preview_normalize_pages
from processors.image_normalizer import normalize_images, preview_normalize_images
from processors.image_normalizer import (
normalize_images,
preview_normalize_images,
uniformize_images,
preview_uniformize_images,
)
class Pipeline:
@@ -50,6 +55,10 @@ class Pipeline:
return {"renames": renames}
elif step == "normalize_images":
conversions = preview_uniformize_images(temp_dir, self.desired_image_format)
return {"conversions": conversions, "target_ext": self.desired_image_format}
elif step == "convert_images":
conversions = preview_normalize_images(temp_dir, self.desired_image_format)
return {"conversions": conversions, "target_ext": self.desired_image_format}
@@ -107,6 +116,19 @@ class Pipeline:
preview = self._compute_preview("normalize_images", temp_dir, step_results)
if preview.get("conversions"):
if confirm_fn is None or confirm_fn("normalize_images", preview):
img_result = uniformize_images(temp_dir, self.desired_image_format)
step_results.append(img_result)
if img_result.errors:
return ComicResult(
original_path=path, final_path=None, steps=step_results
)
if img_result.changed:
any_changed = True
if "convert_images" in self.steps:
preview = self._compute_preview("convert_images", temp_dir, step_results)
if preview.get("conversions"):
if confirm_fn is None or confirm_fn("convert_images", preview):
img_result = normalize_images(temp_dir, self.desired_image_format)
step_results.append(img_result)
if img_result.errors:
+6 -3
View File
@@ -30,7 +30,7 @@ def _print_preview(step: str, preview: dict, formato: str) -> None:
print(f" ... y {n - 10} más")
print(f"Formato final del archivo: {fmt}")
elif step == "normalize_images":
elif step in ("normalize_images", "convert_images"):
conversions = preview["conversions"]
target_ext = preview["target_ext"].lstrip(".")
lossless = " (sin pérdida)" if target_ext.lower() == "png" else ""
@@ -65,6 +65,7 @@ def parse_args():
parser.add_argument("--formato", choices=["cbz", "cbr"], default="cbz")
parser.add_argument("--renumerar", action="store_true")
parser.add_argument("--uniformizar-imagenes", action="store_true")
parser.add_argument("--convertir-imagenes", action="store_true")
parser.add_argument("--formato-imagen", choices=["jpg", "png", "webp"], default="png")
parser.add_argument("--no-preguntar", action="store_true")
@@ -94,10 +95,12 @@ def main():
steps = []
if args.limpiar or args.estandarizar:
steps.append("clean")
if args.renumerar:
if args.renumerar or args.estandarizar:
steps.append("normalize_pages")
if args.uniformizar_imagenes:
if args.uniformizar_imagenes or args.estandarizar:
steps.append("normalize_images")
if args.convertir_imagenes:
steps.append("convert_images")
if args.convertir or args.estandarizar:
steps.append("convert")
+26
View File
@@ -87,3 +87,29 @@ def normalize_images(work_dir: str, target_ext: str = ".jpg") -> StepResult:
changed = True
return StepResult(step="normalize_images", changed=changed, details=details)
def _detected_formats(work_dir: str) -> set[str]:
"""Devuelve el conjunto de extensiones de imagen presentes en work_dir (normalizando .jpeg → .jpg)."""
formats = set()
for fname in os.listdir(work_dir):
ext = os.path.splitext(fname)[1].lower()
if ext == ".jpeg":
ext = ".jpg"
if ext in IMAGE_EXTENSIONS:
formats.add(ext)
return formats
def preview_uniformize_images(work_dir: str, target_ext: str) -> list[tuple[str, str]]:
"""Como preview_normalize_images pero devuelve [] si las imágenes ya son uniformes."""
if len(_detected_formats(work_dir)) <= 1:
return []
return preview_normalize_images(work_dir, target_ext)
def uniformize_images(work_dir: str, target_ext: str = ".jpg") -> StepResult:
"""Como normalize_images pero solo actúa si hay formatos mixtos."""
if len(_detected_formats(work_dir)) <= 1:
return StepResult(step="normalize_images", changed=False)
return normalize_images(work_dir, target_ext)