File size: 5,520 Bytes
2e9c550
c10bf88
 
 
f30d0fa
c10bf88
2e9c550
 
814058a
2e9c550
 
b35d379
2e9c550
 
c10bf88
2e9c550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import gradio as gr
import requests
import os
from moviepy.editor import VideoFileClip, concatenate_videoclips
import tempfile

# ---------------- تنظیمات ----------------
PIXABAY_API_KEY = os.getenv("PIXABAY_API_KEY")  # در Settings → Secrets در Hugging Face بگذار

if not PIXABAY_API_KEY:
    raise ValueError("لطفاً PIXABAY_API_KEY را در Secrets فضای خود قرار دهید!")

VIDEO_SEARCH_URL = "https://pixabay.com/api/videos/"
CLIP_DURATION = 3.0  # ثانیه

def download_video(url, temp_dir):
    """دانلود ویدیو و برگرداندن مسیر فایل"""
    response = requests.get(url, stream=True)
    if response.status_code != 200:
        return None
    
    temp_path = os.path.join(temp_dir, "clip.mp4")
    with open(temp_path, "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)
    return temp_path

def search_pixabay_videos(query, per_page=10):
    params = {
        "key": PIXABAY_API_KEY,
        "q": query,
        "video_type": "all",     # all / film / animation
        "per_page": per_page,
        "min_duration": 4,       # حداقل ۴ ثانیه که بتوان ۳ ثانیه برداشت
        "safesearch": "true"
    }
    
    try:
        r = requests.get(VIDEO_SEARCH_URL, params=params, timeout=15)
        r.raise_for_status()
        data = r.json()
        
        videos = []
        for hit in data.get("hits", []):
            # بهترین کیفیت ممکن (large یا medium)
            vid = hit.get("videos", {})
            if "large" in vid and vid["large"]["url"]:
                videos.append(vid["large"]["url"])
            elif "medium" in vid and vid["medium"]["url"]:
                videos.append(vid["medium"]["url"])
        
        return videos[:8]  # حداکثر ۸ تا ویدیو بگیریم که پردازش سنگین نشود
    except Exception as e:
        print(e)
        return []

def create_montage(keywords):
    if not keywords.strip():
        return None, "لطفاً کلمات کلیدی وارد کنید"
    
    query = keywords.strip().replace(",", " ").replace("  ", " ")
    
    with tempfile.TemporaryDirectory() as tmpdirname:
        video_urls = search_pixabay_videos(query)
        
        if not video_urls:
            return None, f"هیچ ویدیویی برای '{query}' پیدا نشد."
        
        clips = []
        count = 0
        
        for url in video_urls:
            try:
                path = download_video(url, tmpdirname)
                if not path:
                    continue
                
                clip = VideoFileClip(path)
                
                # اگر ویدیو کوتاه‌تر از ۳ ثانیه بود → skip
                if clip.duration < CLIP_DURATION:
                    clip.close()
                    continue
                
                # برش ۳ ثانیه (مثلاً از وسط یا اول)
                start = max(0, (clip.duration - CLIP_DURATION) / 2)  # وسط ویدیو
                subclip = clip.subclip(start, start + CLIP_DURATION)
                
                clips.append(subclip)
                count += 1
                
                clip.close()
                if count >= 5:  # مثلاً حداکثر ۵ قطعه → حدود ۱۵ ثانیه
                    break
                    
            except Exception as e:
                print(f"خطا در پردازش ویدیو: {e}")
                continue
        
        if not clips:
            return None, "متأسفانه نتوانستیم ویدیوهای مناسب دانلود/برش دهیم."
        
        try:
            final_clip = concatenate_videoclips(clips, method="compose")
            
            # خروجی موقت
            output_path = os.path.join(tmpdirname, "montage.mp4")
            final_clip.write_videofile(output_path,
                                     codec="libx264",
                                     audio_codec="aac",
                                     fps=24,
                                     preset="medium",
                                     threads=4,
                                     logger=None)
            
            return output_path, f"ویدیو با موفقیت ساخته شد ({len(clips)} قطعه × ۳ ثانیه)"
        
        except Exception as e:
            return None, f"خطا در ساخت ویدیو: {str(e)}"
        
        finally:
            # تمیز کردن حافظه
            for c in clips:
                c.close()
            if 'final_clip' in locals():
                final_clip.close()

# ---------------- رابط کاربری Gradio ----------------
with gr.Blocks(title="Pixabay Video Montage") as demo:
    gr.Markdown("# ساخت مونتاژ ویدیو از Pixabay\nکلمات کلیدی را وارد کنید (مثال: nature, sunset, drone)")
    
    textbox = gr.Textbox(label="کلمات کلیدی (با کاما یا فاصله جدا کنید)", placeholder="ocean waves, beach, sunset")
    
    btn = gr.Button("ساخت ویدیو (۳ ثانیه از هر کلیپ)")
    
    output_video = gr.Video(label="ویدیوی نهایی")
    status = gr.Textbox(label="وضعیت")
    
    btn.click(
        fn=create_montage,
        inputs=textbox,
        outputs=[output_video, status],
        api_name="make_montage"
    )

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