| import os |
| import time |
| import numpy as np |
| import librosa |
| import gradio as gr |
|
|
| |
| os.environ["IMAGEMAGICK_BINARY"] = r"C:\Program Files\ImageMagick-7.1.2-Q16-HDRI\magick.exe" |
|
|
| |
| try: |
| from moviepy.editor import VideoFileClip, concatenate_videoclips |
| except ImportError: |
| from moviepy import VideoFileClip, concatenate_videoclips |
|
|
|
|
| def safe_subclip(clip, start, end): |
| """دالة ذكية تكتشف اسم الدالة الصحيح بناءً على إصدار المكتبة""" |
| if hasattr(clip, 'subclipped'): |
| return clip.subclipped(start, end) |
| return clip.subclip(start, end) |
|
|
|
|
|
|
| def remove_silence(video_path, threshold=-30, progress=gr.Progress()): |
| if not video_path: |
| return None, "يرجى رفع فيديو أولاً." |
|
|
| output_filename = f"final_result_{int(time.time())}.mp4" |
| video = None |
| final_video = None |
|
|
| try: |
| progress(0, desc="تحميل الفيديو...") |
| video = VideoFileClip(video_path) |
|
|
| progress(0.2, desc="تحليل موجات الصوت...") |
| fps_audio = 22050 |
| audio_array = video.audio.to_soundarray(fps=fps_audio) |
|
|
| if len(audio_array.shape) > 1: |
| audio_array = np.mean(audio_array, axis=1) |
|
|
| progress(0.4, desc="اكتشاف مناطق الصمت...") |
| intervals = librosa.effects.split(audio_array, top_db=abs(threshold)) |
|
|
| if len(intervals) == 0: |
| return None, "تنبيه: الفيديو صامت تماماً بناءً على الإعدادات الحالية." |
|
|
| progress(0.5, desc="تجميع المقاطع الصوتية...") |
| keep_clips = [] |
| for start_idx, end_idx in intervals: |
| t_start = start_idx / fps_audio |
| t_end = end_idx / fps_audio |
| keep_clips.append(safe_subclip(video, t_start, t_end)) |
|
|
| progress(0.7, desc="بدء التصدير النهائي (قد يستغرق وقتاً)...") |
| final_video = concatenate_videoclips(keep_clips) |
|
|
| final_video.write_videofile( |
| output_filename, |
| fps=video.fps, |
| codec="libx264", |
| audio_codec="aac", |
| threads=4, |
| preset="ultrafast", |
| logger=None |
| ) |
|
|
| progress(1.0, desc="اكتملت العملية!") |
|
|
| video.close() |
| final_video.close() |
|
|
| return output_filename, "تمت المعالجة بنجاح! يمكنك تحميل الفيديو الآن." |
|
|
| except Exception as e: |
| if video: |
| video.close() |
| return None, f"خطأ تقني: {str(e)}" |
|
|
| |
| with gr.Blocks(theme=gr.themes.Soft(), title="SilentCut Pro") as demo: |
| gr.Markdown(""" |
| # 🎬 SilentCut Pro |
| ### حذف الصمت آلياً | سرعة عالية | جودة فائقة |
| """) |
|
|
| with gr.Row(): |
| with gr.Column(): |
| v_in = gr.Video(label="ارفع الفيديو (MP4, AVI, MOV)") |
| slider = gr.Slider( |
| minimum=-60, maximum=-10, value=-30, |
| label="حساسية الصمت (ديسيبل)", |
| info="قلل الرقم (مثلاً -40) إذا كان البرنامج يقص أجزاء من كلامك." |
| ) |
| btn = gr.Button("🚀 بدء حذف الصمت", variant="primary") |
|
|
| with gr.Column(): |
| v_out = gr.Video(label="الفيديو الناتج") |
| status = gr.Textbox(label="الحالة والتقدم", interactive=False) |
|
|
| btn.click( |
| fn=remove_silence, |
| inputs=[v_in, slider], |
| outputs=[v_out, status] |
| ) |
|
|
| if __name__ == "__main__": |
| |
| demo.launch(share=False) |