File size: 4,758 Bytes
5e77470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import whisper
import os
import subprocess
import gradio as gr
import shutil

def process_video_source(num_clips, duration, mode, url, uploaded_file, progress=gr.Progress()):
    try:
        progress(0, desc="Initializing...")
        output_template = "source_video.mp4"
        
        # Determine Source: File Upload takes priority over URL
        if uploaded_file is not None:
            progress(0.1, desc="Processing uploaded file...")
            if os.path.exists(output_template):
                os.remove(output_template)
            shutil.copy(uploaded_file.name, output_template)
            video_path = output_template
        elif url:
            progress(0.1, desc="Downloading from YouTube...")
            video_path = download_youtube(url)
        else:
            return "❌ Error: Please provide either a YouTube URL or upload a video file.", []

        if video_path is None or not os.path.exists(video_path):
            return "❌ Source acquisition failed. Check URL or File.", []

        # 2. Transcribe
        progress(0.3, desc="Analyzing Audio (Whisper)...")
        model = whisper.load_model("base")
        result = model.transcribe(video_path, fp16=False)
        
        # 3. Logic
        progress(0.6, desc="Finding best segments...")
        best_parts = get_best_segments(result['segments'], int(num_clips), int(duration))
        
        output_dir = f"clips_{mode}"
        if os.path.exists(output_dir):
            shutil.rmtree(output_dir)
        os.makedirs(output_dir)

        # 4. Export
        clip_paths = []
        for i, clip in enumerate(best_parts):
            progress(0.6 + (0.3 * (i/len(best_parts))), desc=f"Exporting Clip {i+1}...")
            output_name = os.path.abspath(f"{output_dir}/clip_{i+1}.mp4")
            start_time = clip['start']
            
            if mode.lower() == "short":
                vf_filter = "crop=ih*(9/16):ih"
                cmd = f"ffmpeg -ss {start_time} -t {int(duration)} -i {video_path} -vf '{vf_filter}' -c:v libx264 -crf 23 -c:a aac -y {output_name}"
            else:
                cmd = f"ffmpeg -ss {start_time} -t {int(duration)} -i {video_path} -c:v libx264 -c:a aac -y {output_name}"
                
            subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            clip_paths.append(output_name)

        progress(1.0, desc="Done!")
        return f"βœ… Success! Created {len(clip_paths)} clips.", clip_paths
    
    except Exception as e:
        return f"❌ Error: {str(e)}", []

def download_youtube(url):
    output_template = "source_video.mp4"
    cookie_arg = "--cookies cookies.txt" if os.path.exists("cookies.txt") else ""
    cmd = f'yt-dlp {cookie_arg} -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" --no-check-certificate -o "{output_template}" "{url}"'
    result = subprocess.run(cmd, shell=True)
    return output_template if result.returncode == 0 else None

def get_best_segments(segments, num_clips, duration):
    scored_segments = []
    for s in segments:
        score = len(s['text'].split()) / (s['end'] - s['start'] + 0.1)
        scored_segments.append({'start': s['start'], 'score': score})
    
    scored_segments.sort(key=lambda x: x['score'], reverse=True)
    final = []
    for s in scored_segments:
        if len(final) >= int(num_clips): break
        if not any(abs(s['start'] - f['start']) < int(duration) for f in final):
            final.append(s)
    return final

# --- Gradio Interface ---
with gr.Blocks(title="Bulk Viral Video Generator") as demo:
    gr.Markdown("# πŸŽ₯ Bulk Viral Video Generator")
    
    with gr.Row():
        with gr.Column():
            yt_url = gr.Textbox(label="YouTube URL (Optional if uploading file)", placeholder="Enter URL here...")
            file_input = gr.File(label="OR Upload Video File", file_types=["video"])
            
            with gr.Row():
                num_shorts = gr.Number(label="Number of Shorts", value=5, precision=0)
                duration = gr.Number(label="Seconds per Clip", value=60, precision=0)
            
            mode = gr.Radio(choices=["short", "long"], label="Format", value="short")
            btn = gr.Button("πŸš€ Generate Viral Clips", variant="primary")
        
        with gr.Column():
            status = gr.Textbox(label="Status")
            gallery = gr.Gallery(label="Generated Clips", columns=2, height="auto")

    btn.click(
        fn=process_video_source, 
        inputs=[num_shorts, duration, mode, yt_url, file_input], 
        outputs=[status, gallery]
    )

if __name__ == "__main__":
    # Listening on 0.0.0.0 for local network/docker access
    demo.launch(server_name="0.0.0.0", server_port=7860, share=False)