| | 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) |