88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
"""
|
|
Regenerate one specific shot and re-concatenate the hero reel.
|
|
Usage: python3 tools/regen-shot.py shot-02-staircase
|
|
"""
|
|
import os, sys, time, subprocess
|
|
from google import genai
|
|
from google.genai import types
|
|
import urllib.request
|
|
|
|
API_KEY = os.environ.get("GEMINI_API_KEY", "")
|
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
|
CLIPS_DIR = os.path.join(BASE_DIR, "assets", "videos", "hero", "clips")
|
|
REEL_OUT = os.path.join(BASE_DIR, "assets", "videos", "hero", "hero-reel.mp4")
|
|
|
|
if not API_KEY:
|
|
print("Set GEMINI_API_KEY env var"); sys.exit(1)
|
|
|
|
# Import SHOTS from gen-video.py (dash in name requires importlib)
|
|
import importlib.util
|
|
spec = importlib.util.spec_from_file_location(
|
|
"gen_video", os.path.join(os.path.dirname(__file__), "gen-video.py")
|
|
)
|
|
_mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(_mod)
|
|
SHOTS = _mod.SHOTS
|
|
|
|
shot_name = sys.argv[1] if len(sys.argv) > 1 else None
|
|
target = next((s for s in SHOTS if s["name"] == shot_name), None)
|
|
if not target:
|
|
print(f"Shot '{shot_name}' not found. Available: {[s['name'] for s in SHOTS]}")
|
|
sys.exit(1)
|
|
|
|
client = genai.Client(api_key=API_KEY)
|
|
out_path = os.path.join(CLIPS_DIR, f"{target['name']}.mp4")
|
|
|
|
print(f"Regenerating {target['name']}...")
|
|
op = client.models.generate_videos(
|
|
model="veo-3.0-generate-001",
|
|
prompt=target["prompt"],
|
|
config=types.GenerateVideosConfig(
|
|
aspect_ratio="16:9", resolution="720p",
|
|
duration_seconds=6, number_of_videos=1,
|
|
),
|
|
)
|
|
elapsed = 0
|
|
while not op.done:
|
|
print(f" Waiting... ({elapsed}s)")
|
|
time.sleep(15); elapsed += 15
|
|
op = client.operations.get(op)
|
|
|
|
if not (op.response and op.response.generated_videos):
|
|
print("No video returned"); sys.exit(1)
|
|
|
|
vid = op.response.generated_videos[0].video
|
|
video_bytes = None
|
|
try:
|
|
video_bytes = client.files.download(file=vid)
|
|
except Exception:
|
|
pass
|
|
if video_bytes:
|
|
with open(out_path, "wb") as f: f.write(video_bytes)
|
|
elif hasattr(vid, "uri") and vid.uri:
|
|
uri = vid.uri + ("&" if "?" in vid.uri else "?") + f"key={API_KEY}"
|
|
urllib.request.urlretrieve(uri, out_path)
|
|
else:
|
|
print("Download failed"); sys.exit(1)
|
|
|
|
print(f"Saved {out_path} ({os.path.getsize(out_path)//1024}KB)")
|
|
|
|
# Re-concat in shot order
|
|
clips = [os.path.join(CLIPS_DIR, f"{s['name']}.mp4") for s in SHOTS
|
|
if os.path.exists(os.path.join(CLIPS_DIR, f"{s['name']}.mp4"))]
|
|
list_file = os.path.join(CLIPS_DIR, "concat.txt")
|
|
with open(list_file, "w") as f:
|
|
for c in clips: f.write(f"file '{c}'\n")
|
|
|
|
print(f"Concatenating {len(clips)} clips...")
|
|
r = subprocess.run(
|
|
["ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", list_file,
|
|
"-c:v", "libx264", "-crf", "22", "-preset", "fast",
|
|
"-movflags", "+faststart", REEL_OUT],
|
|
capture_output=True, text=True
|
|
)
|
|
if r.returncode == 0:
|
|
print(f"Reel updated: {REEL_OUT} ({os.path.getsize(REEL_OUT)//1024}KB)")
|
|
else:
|
|
print(f"ffmpeg error: {r.stderr[-200:]}")
|