Spaces:
Sleeping
Sleeping
File size: 4,502 Bytes
fed2287 4887e95 efb68a6 a4b5d8d 4814522 2da681a efb68a6 4814522 efb68a6 f4082e2 4814522 6d9efef ded726e 4814522 fed2287 ded726e 4814522 efb68a6 4814522 2da681a 0267b8a 4814522 ded726e 4814522 ded726e 2da681a 4814522 ded726e 4814522 ded726e 2da681a ded726e 4887e95 4814522 ded726e 4814522 4887e95 4814522 2da681a 6dc2268 4887e95 ded726e 4887e95 2da681a fed2287 2da681a ded726e 2da681a fed2287 4887e95 ded726e 4887e95 f4082e2 6d9efef ded726e 2da681a 4887e95 ded726e 4814522 fed2287 ded726e fed2287 2da681a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import gradio as gr
import subprocess
import os
import uuid
import json
# Auto-install Node modules
if not os.path.exists("node_modules"):
subprocess.run(["npm", "install"], check=True)
def get_video_dimensions(url):
try:
cmd = [
"ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=width,height", "-of", "json", url
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
data = json.loads(result.stdout)
return data['streams'][0]['width'], data['streams'][0]['height']
except:
return 0, 0
def process_video(query, start_time, end_time, mute_audio, progress=gr.Progress()):
if not query:
return None, "β οΈ Enter a keyword."
progress(0, desc="π Searching Pinterest...")
search_query = query if "video" in query.lower() else f"{query} video"
try:
# 1. Scrape URLs
result = subprocess.run(
["node", "scraper.js", search_query],
capture_output=True, text=True, timeout=240
)
all_urls = [line.strip() for line in result.stdout.split('\n') if line.strip().startswith("http")]
if not all_urls:
return None, "β No videos found."
selected_url = None
needs_crop = False
# --- PHASE 1: SEARCH FOR PORTRAIT FIRST ---
progress(0.2, desc="π Phase 1: Looking for Portrait video...")
for url in all_urls:
w, h = get_video_dimensions(url)
if h > w: # Found Portrait
selected_url = url
needs_crop = False
break
# --- PHASE 2: SEARCH FOR LANDSCAPE FALLBACK ---
if not selected_url:
progress(0.5, desc="π Phase 2: No Portrait found. Looking for Landscape to crop...")
for url in all_urls:
w, h = get_video_dimensions(url)
if w > h: # Found Landscape
selected_url = url
needs_crop = True
break
if not selected_url:
return None, "β No videos found in any orientation."
# 3. Process Video
progress(0.8, desc="βοΈ Final Processing...")
output_filename = f"output_{uuid.uuid4().hex[:5]}.mp4"
# Define Filter Logic
if needs_crop:
# Crop middle to 9:16 (ih*9/16 is the width based on height)
# We then scale it to a standard height like 1280 to keep it clean
vf_filter = "crop=ih*9/16:ih,scale=-1:1280,unsharp=3:3:1.2:3:3:0.0,format=yuv420p"
status_msg = "β
Found Landscape: Cropped to 9:16"
else:
# Already Portrait: Just sharpen and standardize
vf_filter = "scale=-1:1280,unsharp=3:3:1.2:3:3:0.0,format=yuv420p"
status_msg = "β
Found Portrait: Keeping original ratio"
ffmpeg_cmd = [
"ffmpeg",
"-ss", str(start_time),
"-to", str(end_time) if end_time > 0 else "999",
"-i", selected_url,
"-vf", vf_filter,
"-c:v", "libx264",
"-crf", "18",
"-preset", "veryfast",
"-y", output_filename
]
if mute_audio:
ffmpeg_cmd.insert(-1, "-an")
else:
ffmpeg_cmd.insert(-1, "-c:a")
ffmpeg_cmd.insert(-1, "aac")
subprocess.run(ffmpeg_cmd, check=True)
return output_filename, status_msg
except Exception as e:
return None, f"β Error: {str(e)}"
# --- UI ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# π Pinterest Smart 9:16 Downloader")
gr.Markdown("Prioritizes Vertical videos. If only Horizontal are found, it crops the center to 9:16.")
with gr.Row():
with gr.Column():
q = gr.Textbox(label="Topic", placeholder="e.g. Minecraft Gameplay")
with gr.Row():
s = gr.Number(label="Start (sec)", value=0)
e = gr.Number(label="End (sec)", value=5)
mute = gr.Checkbox(label="Mute Audio", value=False)
btn = gr.Button("π Smart Search & Process", variant="primary")
with gr.Column():
out_v = gr.Video(label="9:16 Result")
out_s = gr.Textbox(label="Status")
btn.click(process_video, [q, s, e, mute], [out_v, out_s])
if __name__ == "__main__":
demo.launch() |