afegit convertir-imagenes
This commit is contained in:
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user