Replace stub CLI with real compression engine
This commit is contained in:
+79
-3
@@ -4,17 +4,93 @@ import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from .media import classify_path, find_ffmpeg_tools, human_size
|
||||
from .models import ImageOptions, VideoOptions, MediaKind
|
||||
from .processing import compress_image, compress_video
|
||||
|
||||
|
||||
def _collect_inputs(paths):
|
||||
"""Expand directories into media files."""
|
||||
files = []
|
||||
for raw in paths:
|
||||
p = Path(raw)
|
||||
if p.is_dir():
|
||||
for child in sorted(p.rglob("*")):
|
||||
if child.is_file() and classify_path(child):
|
||||
files.append(child)
|
||||
elif p.is_file() and classify_path(p):
|
||||
files.append(p)
|
||||
else:
|
||||
print(f"Skipping unsupported file: {raw}", file=sys.stderr)
|
||||
return files
|
||||
|
||||
|
||||
def _output_path(source: Path, output_dir: Path | None) -> Path:
|
||||
if output_dir:
|
||||
return output_dir / source.name
|
||||
return source.with_name(source.stem + "_compressed" + source.suffix)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Compress media files from the command line.")
|
||||
parser.add_argument("input", nargs="+", help="Files or directories to compress")
|
||||
parser.add_argument("-o", "--output", help="Output directory")
|
||||
parser.add_argument("-q", "--quality", type=int, default=80, help="Compression quality (1-100)")
|
||||
parser.add_argument("--batch", action="store_true", help="Process files in batch mode")
|
||||
parser.add_argument("--format", choices=["original", "jpeg", "webp", "png"], default="original", help="Output image format")
|
||||
parser.add_argument("--codec", choices=["h264", "h265", "vp9", "av1"], default="h264", help="Video codec")
|
||||
parser.add_argument("--resize", choices=["original", "fit", "percent"], default="original", help="Image resize mode")
|
||||
parser.add_argument("--max-width", type=int, default=1920, help="Max width for fit resize")
|
||||
parser.add_argument("--max-height", type=int, default=1080, help="Max height for fit resize")
|
||||
parser.add_argument("--scale", type=int, default=80, help="Scale percent for percent resize")
|
||||
parser.add_argument("--keep-metadata", action="store_true", help="Preserve metadata")
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"Bolt-Compress CLI: {len(args.input)} item(s), quality {args.quality}")
|
||||
# Compression engine hooks in here
|
||||
return 0
|
||||
files = _collect_inputs(args.input)
|
||||
if not files:
|
||||
print("No supported media files found.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
output_dir = Path(args.output) if args.output else None
|
||||
if output_dir:
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
tools = find_ffmpeg_tools()
|
||||
image_opts = ImageOptions(
|
||||
output_format=args.format,
|
||||
quality=args.quality,
|
||||
resize_mode=args.resize,
|
||||
max_width=args.max_width,
|
||||
max_height=args.max_height,
|
||||
scale_percent=args.scale,
|
||||
keep_metadata=args.keep_metadata,
|
||||
)
|
||||
video_opts = VideoOptions(
|
||||
codec=args.codec,
|
||||
quality=args.quality,
|
||||
keep_metadata=args.keep_metadata,
|
||||
)
|
||||
|
||||
total = len(files)
|
||||
succeeded = 0
|
||||
for i, source in enumerate(files, 1):
|
||||
kind = classify_path(source)
|
||||
dest = _output_path(source, output_dir)
|
||||
print(f"[{i}/{total}] {source.name} -> {dest.name}")
|
||||
try:
|
||||
if kind == MediaKind.IMAGE:
|
||||
compress_image(source, dest, image_opts)
|
||||
else:
|
||||
compress_video(source, dest, video_opts, tools)
|
||||
saved = source.stat().st_size - dest.stat().st_size
|
||||
print(f" Done: {human_size(source.stat().st_size)} -> {human_size(dest.stat().st_size)} (saved {human_size(max(0, saved))})")
|
||||
succeeded += 1
|
||||
except Exception as exc:
|
||||
print(f" Failed: {exc}", file=sys.stderr)
|
||||
|
||||
print(f"\n{succeeded}/{total} files compressed successfully.")
|
||||
return 0 if succeeded == total else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
Reference in New Issue
Block a user