akhaliq HF Staff commited on
Commit
f7a8ccc
·
verified ·
1 Parent(s): c0ba04b

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +137 -0
app.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A minimal, self-contained Gradio video editor that allows:
3
+ 1. Uploading one or more videos.
4
+ 2. Trimming each video to a start/end time.
5
+ 3. Concatenating the trimmed clips in the order supplied.
6
+ 4. Downloading the final edited video.
7
+
8
+ Requirements (install once):
9
+ pip install gradio moviepy==1.0.3
10
+
11
+ Run:
12
+ python video_editor.py
13
+ """
14
+
15
+ import tempfile
16
+ import os
17
+ from typing import List, Tuple
18
+
19
+ import gradio as gr
20
+ from moviepy.editor import VideoFileClip, concatenate_videoclips
21
+
22
+
23
+ def _time_to_seconds(time_str: str) -> float:
24
+ """Convert HH:MM:SS[.ms] → seconds (float)."""
25
+ parts = list(map(float, reversed(time_str.split(":"))))
26
+ return sum(v * 60 ** idx for idx, v in enumerate(parts))
27
+
28
+
29
+ def edit_videos(
30
+ videos: List[str],
31
+ trims: List[Tuple[str, str]],
32
+ ) -> str:
33
+ """
34
+ Create a single edited video from the list of uploaded videos
35
+ and corresponding (start, end) times.
36
+
37
+ Returns the file path of the final video.
38
+ """
39
+
40
+ if not videos:
41
+ raise ValueError("At least one video is required.")
42
+
43
+ if len(videos) != len(trims):
44
+ raise ValueError("Each video must have a start/end time pair.")
45
+
46
+ clips = []
47
+ for vid_path, (start_str, end_str) in zip(videos, trims):
48
+ start = _time_to_seconds(start_str)
49
+ end = _time_to_seconds(end_str)
50
+ clip = VideoFileClip(vid_path).subclip(start, end)
51
+ clips.append(clip)
52
+
53
+ final = concatenate_videoclips(clips)
54
+
55
+ # Save to a temporary file with a unique name
56
+ out_path = os.path.join(
57
+ tempfile.gettempdir(),
58
+ "edited_video.mp4"
59
+ )
60
+ final.write_videofile(out_path, codec="libx264", audio_codec="aac")
61
+
62
+ # Close clips to release file handles
63
+ for c in clips:
64
+ c.close()
65
+ final.close()
66
+
67
+ return out_path
68
+
69
+
70
+ def gradio_interface():
71
+ with gr.Blocks(title="Video Editor") as demo:
72
+ gr.Markdown("## Simple Gradio Video Editor")
73
+ gr.Markdown(
74
+ "Upload one or more videos. \n"
75
+ "Provide the **start** and **end** time (HH:MM:SS) for each clip. \n"
76
+ "The clips will be concatenated in the order given."
77
+ )
78
+
79
+ with gr.Row():
80
+ with gr.Column(scale=2):
81
+ video_files = gr.File(
82
+ label="Upload videos",
83
+ file_count="multiple",
84
+ file_types=["video"],
85
+ type="filepath",
86
+ )
87
+
88
+ # Dynamic UI for trims
89
+ trim_rows = gr.State([])
90
+
91
+ def _update_trim_inputs(videos):
92
+ rows = []
93
+ for idx, v in enumerate(videos or []):
94
+ with gr.Row():
95
+ start = gr.Textbox(
96
+ label=f"Start time #{idx+1}",
97
+ value="00:00:00",
98
+ scale=1,
99
+ )
100
+ end = gr.Textbox(
101
+ label=f"End time #{idx+1}",
102
+ value="00:00:05",
103
+ scale=1,
104
+ )
105
+ rows.append((start, end))
106
+ return rows
107
+
108
+ trim_inputs_placeholder = gr.HTML() # dummy; we will render rows
109
+
110
+ # Render trim inputs after file upload
111
+ video_files.change(
112
+ fn=_update_trim_inputs,
113
+ inputs=video_files,
114
+ outputs=trim_inputs_placeholder,
115
+ )
116
+
117
+ with gr.Column(scale=1):
118
+ output_video = gr.Video(label="Edited Video")
119
+ edit_btn = gr.Button("Edit & Download", variant="primary")
120
+
121
+ # Submit
122
+ def _on_edit(videos):
123
+ # Re-create trim tuples based on current videos
124
+ rows = _update_trim_inputs(videos)
125
+ trims = [
126
+ (start.value, end.value) for start, end in rows
127
+ ]
128
+ out_path = edit_videos(videos, trims)
129
+ return out_path
130
+
131
+ edit_btn.click(_on_edit, inputs=[video_files], outputs=output_video)
132
+
133
+ demo.launch()
134
+
135
+
136
+ if __name__ == "__main__":
137
+ gradio_interface()