File size: 4,603 Bytes
fed2287
 
 
4887e95
efb68a6
a4b5d8d
f6e88f5
2da681a
 
 
17e1071
efb68a6
f6e88f5
 
 
 
efb68a6
 
17e1071
f6e88f5
 
6d9efef
d56f850
 
f6e88f5
d56f850
 
f6e88f5
d56f850
 
f6e88f5
d56f850
f6e88f5
6dc2268
17e1071
f6e88f5
 
 
 
120d8f4
f6e88f5
17e1071
d56f850
f6e88f5
 
d56f850
 
 
 
 
 
 
f6e88f5
d56f850
17e1071
d56f850
f6e88f5
d56f850
f6e88f5
 
d56f850
 
 
 
 
 
 
 
 
 
fed2287
f6e88f5
d56f850
f6e88f5
 
d56f850
 
 
 
 
 
 
 
 
 
 
17e1071
d56f850
 
 
 
 
f6e88f5
d56f850
 
 
 
b331259
17e1071
120d8f4
d56f850
f6e88f5
fed2287
4887e95
f6e88f5
17e1071
4887e95
f6e88f5
 
17e1071
 
f6e88f5
4887e95
17e1071
 
120d8f4
17e1071
fed2287
17e1071
 
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
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 run_scraper(mode, query, orientation="Any"):
    """Helper to run the Node.js scraper in specific mode"""
    try:
        # Calls: node scraper.js [mode] [query] [orientation]
        cmd = ["node", "scraper.js", mode, query, orientation]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=240)
        urls = [line.strip() for line in result.stdout.split('\n') if line.strip().startswith("http")]
        return urls
    except Exception as e:
        print(f"Scraper Error ({mode}): {e}")
        return []

def process_video(query, orientation, start_time, end_time, mute_audio, progress=gr.Progress()):
    if not query:
        return None, "⚠️ Enter a keyword."
    
    search_query = query if "video" in query.lower() else f"{query} video"
    
    # --- PHASE 1: PINTEREST SEARCH ---
    progress(0.1, desc="πŸ” Searching Pinterest...")
    all_urls = run_scraper("pinterest", search_query)
    
    # Filter Pinterest Results
    selected_url = None
    for i, url in enumerate(all_urls):
        progress(0.3 + (i/len(all_urls)*0.1), desc=f"Checking Pinterest {i+1}...")
        if orientation == "Any": selected_url = url; break
        w, h = get_video_dimensions(url)
        if orientation == "Portrait" and h > w: selected_url = url; break
        if orientation == "Landscape" and w > h: selected_url = url; break
    
    # --- PHASE 2: PEXELS FALLBACK ---
    if not selected_url:
        progress(0.5, desc=f"⚠️ No {orientation} videos on Pinterest. Switching to Pexels Fallback...")
        
        # We pass the orientation to Pexels so it filters efficiently
        pexels_urls = run_scraper("pexels", query, orientation)
        
        for i, url in enumerate(pexels_urls):
            progress(0.6 + (i/len(pexels_urls)*0.1), desc=f"Checking Pexels {i+1}...")
            # Double check dimensions just to be safe
            if orientation == "Any": selected_url = url; break
            w, h = get_video_dimensions(url)
            if orientation == "Portrait" and h > w: selected_url = url; break
            if orientation == "Landscape" and w > h: selected_url = url; break

    if not selected_url:
        return None, f"❌ Failed. Searched Pinterest & Pexels, but found no {orientation} videos."

    # --- PHASE 3: PROCESSING ---
    progress(0.8, desc="βš™οΈ Processing Video...")
    output_filename = f"final_{uuid.uuid4().hex[:5]}.mp4"
    
    ffmpeg_cmd = [
        "ffmpeg",
        "-ss", str(start_time),
        "-to", str(end_time) if end_time > 0 else "999",
        "-i", selected_url,
        "-vf", "unsharp=3:3:1.2:3:3:0.0,format=yuv420p",
        "-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)
    
    source_name = "Pinterest" if "pinimg" in selected_url else "Pexels"
    return output_filename, f"βœ… Success! Source: {source_name} ({orientation})"

# --- UI ---
with gr.Blocks(theme=gr.themes.Default()) as demo:
    gr.Markdown("# πŸ“Œ Pinterest + Pexels (Auto-Fallback)")
    
    with gr.Row():
        with gr.Column():
            q = gr.Textbox(label="Topic", placeholder="e.g. Ocean Waves")
            o = gr.Dropdown(choices=["Any", "Portrait", "Landscape"], value="Portrait", label="Orientation")
            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("πŸš€ Search & Process", variant="primary")
        
        with gr.Column():
            out_v = gr.Video(label="Result Video")
            out_s = gr.Textbox(label="Status")

    btn.click(process_video, [q, o, s, e, mute], [out_v, out_s])

if __name__ == "__main__":
    demo.launch()