kader1997 commited on
Commit
f43bda0
·
verified ·
1 Parent(s): e15af47

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -30
app.py CHANGED
@@ -1,32 +1,63 @@
1
  import os
2
  import time
 
 
3
  import gradio as gr
4
- from moviepy.editor import VideoFileClip, AudioFileClip
5
 
6
- def sync_audio_video(video_path, audio_path, progress=gr.Progress()):
7
- if not video_path or not audio_path:
8
- return None, "يرجى رفع ملف الفيديو وملف الصوت."
 
 
 
 
 
 
9
 
10
- output_filename = f"synced_video_{int(time.time())}.mp4"
11
- video = None
12
- audio = None
13
- final_video = None
14
 
 
 
 
15
  try:
16
- progress(0.2, desc="تحميل الملفات...")
17
  video = VideoFileClip(video_path)
18
- audio = AudioFileClip(audio_path)
19
-
20
- progress(0.5, desc="جاري المزامنة...")
21
 
22
- # إذا كان الصوت أطول من الفيديو، سيتم قص الصوت
23
- # إذا كان الفيديو أطول، سيتم قص الفيديو ليناسب الصوت (أو العكس حسب رغبتك)
24
- min_duration = min(video.duration, audio.duration)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- # ضبط الصوت للفيديو
27
- final_video = video.set_audio(audio).set_duration(min_duration)
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- progress(0.7, desc="بدء التصدير النهائي...")
30
  final_video.write_videofile(
31
  output_filename,
32
  fps=video.fps,
@@ -38,27 +69,42 @@ def sync_audio_video(video_path, audio_path, progress=gr.Progress()):
38
  )
39
 
40
  video.close()
41
- audio.close()
42
- return output_filename, "تمت المزامنة بنجاح!"
43
 
44
  except Exception as e:
45
- return None, f"خطأ تقني: {str(e)}"
 
46
 
47
- # واجهة Gradio للمزامنة
48
- with gr.Blocks(theme=gr.themes.Soft(), title="Audio Sync Pro") as demo:
49
- gr.Markdown("# 🎵 مزامنة الصوت مع الفيديو")
 
 
 
50
 
51
  with gr.Row():
52
  with gr.Column():
53
- v_in = gr.Video(label="ارفع الفيديو (بدون صوت أو بصوت ضعيف)")
54
- a_in = gr.Audio(label="ارفع ملف الصوت (MP3, WAV)", type="filepath")
55
- btn = gr.Button("🔗 ابدأ المزامنة الآن", variant="primary")
 
 
 
 
 
 
 
 
56
 
57
  with gr.Column():
58
- v_out = gr.Video(label="الفيديو المدمج")
59
- status = gr.Textbox(label="الحالة", interactive=False)
60
 
61
- btn.click(fn=sync_audio_video, inputs=[v_in, a_in], outputs=[v_out, status])
 
 
 
 
62
 
63
  if __name__ == "__main__":
64
  demo.launch()
 
1
  import os
2
  import time
3
+ import numpy as np
4
+ import librosa
5
  import gradio as gr
 
6
 
7
+ # محاولة الاستيراد بأكثر من طريقة لضمان التوافق التام
8
+ try:
9
+ # الطريقة القديمة (MoviePy < 2.0)
10
+ from moviepy.editor import VideoFileClip, AudioFileClip, concatenate_videoclips
11
+ except ImportError:
12
+ # الطريقة الجديدة (MoviePy >= 2.0)
13
+ from moviepy.video.io.VideoFileClip import VideoFileClip
14
+ from moviepy.audio.io.AudioFileClip import AudioFileClip
15
+ from moviepy.video.compositing.concatenate import concatenate_videoclips
16
 
17
+ def sync_and_cut(video_path, audio_path, threshold=-30, progress=gr.Progress()):
18
+ if not video_path:
19
+ return None, "يرجى رفع فيديو أولاً."
 
20
 
21
+ output_filename = f"final_output_{int(time.time())}.mp4"
22
+ video = None
23
+
24
  try:
25
+ progress(0.1, desc="تحميل الملفات...")
26
  video = VideoFileClip(video_path)
 
 
 
27
 
28
+ # 1. إذا تم رفع ملف صوتي خارجي، نقوم بدمجه أولاً
29
+ if audio_path:
30
+ progress(0.3, desc="دمج الصوت الخارجي...")
31
+ external_audio = AudioFileClip(audio_path)
32
+ # مزامنة الطول الزمني
33
+ min_duration = min(video.duration, external_audio.duration)
34
+ video = video.set_audio(external_audio).set_duration(min_duration)
35
+
36
+ # 2. تحليل الصوت لحذف الصمت (اختياري بناءً على رغبة المستخدم)
37
+ progress(0.5, desc="تحليل موجات الصوت...")
38
+ fps_audio = 22050
39
+ audio_array = video.audio.to_soundarray(fps=fps_audio)
40
+ if len(audio_array.shape) > 1:
41
+ audio_array = np.mean(audio_array, axis=1)
42
+
43
+ # اكتشاف الفترات غير الصامتة
44
+ intervals = librosa.effects.split(audio_array, top_db=abs(threshold))
45
 
46
+ if len(intervals) == 0:
47
+ return None, "تنبيه: لم يتم العثور على صوت كافٍ للقص."
48
+
49
+ progress(0.7, desc="تجميع المقاطع النهائية...")
50
+ keep_clips = []
51
+ for start_idx, end_idx in intervals:
52
+ t_start = start_idx / fps_audio
53
+ t_end = end_idx / fps_audio
54
+ # استخدام subclip المتوافق مع كل النسخ
55
+ clip = video.subclip(t_start, t_end) if hasattr(video, 'subclip') else video.subclipped(t_start, t_end)
56
+ keep_clips.append(clip)
57
+
58
+ final_video = concatenate_videoclips(keep_clips)
59
 
60
+ progress(0.8, desc="جاري التصدير (Processing)...")
61
  final_video.write_videofile(
62
  output_filename,
63
  fps=video.fps,
 
69
  )
70
 
71
  video.close()
72
+ return output_filename, "✅ تمت العملية بنجاح!"
 
73
 
74
  except Exception as e:
75
+ if video: video.close()
76
+ return None, f"❌ خطأ: {str(e)}"
77
 
78
+ # --- واجهة المستخدم ---
79
+ with gr.Blocks(theme=gr.themes.Soft(), title="Video Audio Master") as demo:
80
+ gr.Markdown("""
81
+ # 🎬 Video & Audio Master
82
+ **مزامنة صوت خارجي + حذف الصمت التلقائي في خطوة واحدة**
83
+ """)
84
 
85
  with gr.Row():
86
  with gr.Column():
87
+ v_input = gr.Video(label="1. ارفع الفيديو الأصلي")
88
+ a_input = gr.Audio(label="2. ارفع الصوت الجديد (اختياري)", type="filepath")
89
+
90
+ with gr.Accordion("إعدادات متقدمة", open=False):
91
+ slider = gr.Slider(
92
+ minimum=-60, maximum=-10, value=-30,
93
+ label="حساسية حذف الصمت (ديسيبل)",
94
+ info="كلما قل الرقم (مثلاً -50) زادت دقة الحذف."
95
+ )
96
+
97
+ btn = gr.Button("🚀 بدء المعالجة", variant="primary")
98
 
99
  with gr.Column():
100
+ v_output = gr.Video(label="النتيجة النهائية")
101
+ status = gr.Textbox(label="حالة العملية", interactive=False)
102
 
103
+ btn.click(
104
+ fn=sync_and_cut,
105
+ inputs=[v_input, a_input, slider],
106
+ outputs=[v_output, status]
107
+ )
108
 
109
  if __name__ == "__main__":
110
  demo.launch()