sam12345324 commited on
Commit
4ff4cc1
·
verified ·
1 Parent(s): 8c05c55

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +74 -111
main.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import FastAPI, UploadFile, File, Form, HTTPException
2
  from fastapi.responses import FileResponse
3
  import tempfile
4
  import shutil
@@ -12,136 +12,99 @@ from moviepy.editor import (
12
  CompositeAudioClip,
13
  concatenate_audioclips,
14
  )
 
15
 
 
16
  logging.basicConfig(level=logging.INFO)
17
- logger = logging.getLogger(__name__)
18
 
19
- def safe_audio_clip(path):
20
- try:
21
- clip = AudioFileClip(path)
22
- if clip.reader is None or clip.duration is None or clip.duration <= 0:
23
- clip.close()
24
- raise ValueError(f"Invalid or empty audio file: {os.path.basename(path)}")
25
- return clip
26
- except Exception as e:
27
- raise ValueError(f"Failed to load audio file '{os.path.basename(path)}': {str(e)}")
28
 
29
- def merge_videos_and_audios(
30
- video_files, audio_files, orig_vol=1.0, music_vol=0.5, temp_dir=None
31
- ):
32
- try:
33
- # Use temp_dir for output path
34
- output_path = os.path.join(temp_dir, "merged_output.mp4" if video_files else "merged_output.mp3")
35
-
36
- if not video_files and audio_files:
37
- audio_clips = []
38
- for a in audio_files:
39
- try:
40
- audio_clip = safe_audio_clip(a)
41
- audio_clips.append(audio_clip)
42
- except Exception as e:
43
- logger.warning(f"Skipping invalid audio file: {a} → {str(e)}")
44
-
45
- if not audio_clips:
46
- raise ValueError("No valid audio files to merge.")
47
-
48
- final_audio = concatenate_audioclips(audio_clips)
49
- final_audio.write_audiofile(output_path)
50
- for clip in audio_clips:
51
- clip.close()
52
- final_audio.close()
53
- return output_path
54
-
55
- video_clips = [VideoFileClip(v) for v in video_files]
56
- final_video = concatenate_videoclips(video_clips, method="compose")
57
-
58
- if audio_files:
59
- audio_clips = []
60
- for a in audio_files:
61
- try:
62
- audio_clip = safe_audio_clip(a)
63
- audio_clips.append(audio_clip)
64
- except Exception as e:
65
- logger.warning(f"Skipping invalid audio file: {a} → {str(e)}")
66
-
67
- if audio_clips:
68
- final_audio = concatenate_audioclips(audio_clips).volumex(music_vol)
69
- original_audio = final_video.audio.volumex(orig_vol) if final_video.audio else None
70
-
71
- if original_audio:
72
- composite_audio = CompositeAudioClip([original_audio, final_audio])
73
- else:
74
- composite_audio = final_audio
75
-
76
- final_video = final_video.set_audio(composite_audio)
77
-
78
- for clip in audio_clips:
79
- clip.close()
80
- else:
81
- logger.warning("No valid audio files found. Using only video audio (if present).")
82
- if final_video.audio:
83
- final_video = final_video.volumex(orig_vol)
84
- else:
85
- if final_video.audio:
86
- final_video = final_video.volumex(orig_vol)
87
-
88
- final_video.write_videofile(output_path, codec="libx264", audio_codec="aac")
89
-
90
- for clip in video_clips:
91
- clip.close()
92
- final_video.close()
93
-
94
- return output_path
95
 
96
- except Exception as e:
97
- error_msg = f"Error during merge: {str(e)}\n{traceback.format_exc()}"
98
- logger.error(error_msg)
99
- raise RuntimeError(error_msg)
 
 
 
100
 
 
 
 
 
 
 
101
 
102
  app = FastAPI()
103
 
104
  @app.post("/merge")
105
  async def merge_endpoint(
106
- files: list[UploadFile] = File(...),
107
  orig_vol: float = Form(1.0),
108
  music_vol: float = Form(0.5),
109
  ):
110
  temp_dir = tempfile.mkdtemp()
111
  try:
112
- saved_files = []
113
- for uploaded_file in files:
114
- file_path = os.path.join(temp_dir, uploaded_file.filename)
115
- with open(file_path, "wb") as out_file:
116
- content = await uploaded_file.read()
117
- out_file.write(content)
118
- saved_files.append(file_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
- video_files = [f for f in saved_files if f.lower().endswith(".mp4")]
121
- audio_files = [f for f in saved_files if f.lower().endswith((".mp3", ".wav", ".aac", ".m4a", ".ogg"))]
122
-
123
- if len(saved_files) < 2:
124
- raise HTTPException(status_code=400, detail="Please upload at least 2 files (videos or audios).")
125
-
126
- result_path = merge_videos_and_audios(video_files, audio_files, orig_vol, music_vol, temp_dir)
127
-
128
- media_type = "video/mp4" if result_path.lower().endswith(".mp4") else "audio/mpeg"
129
- filename = os.path.basename(result_path)
130
-
131
- return FileResponse(result_path, media_type=media_type, filename=filename)
132
-
133
- except RuntimeError as e:
134
- raise HTTPException(status_code=500, detail=str(e))
135
 
136
  finally:
137
- # Clean up temp directory safely
138
- try:
139
- shutil.rmtree(temp_dir)
140
- except Exception as e:
141
- logger.warning(f"Failed to remove temp directory {temp_dir}: {e}")
142
-
143
 
144
- # Optional logging
145
  def log_api_url():
146
  url = os.getenv("SPACE_PUBLIC_URL")
147
  if url:
 
1
+ from fastapi import FastAPI, UploadFile, File, Form
2
  from fastapi.responses import FileResponse
3
  import tempfile
4
  import shutil
 
12
  CompositeAudioClip,
13
  concatenate_audioclips,
14
  )
15
+ import zipfile
16
 
17
+ # Configure logging
18
  logging.basicConfig(level=logging.INFO)
19
+ logger = logging.getLogger("main")
20
 
21
+ # Merge function
22
+ def merge_videos_and_audios(video_paths, audio_paths, output_path):
23
+ video_clips = [VideoFileClip(vp) for vp in video_paths]
 
 
 
 
 
 
24
 
25
+ audio_clips = []
26
+ for ap in audio_paths:
27
+ try:
28
+ audio_clip = AudioFileClip(ap)
29
+ audio_clips.append(audio_clip)
30
+ except Exception as e:
31
+ logger.warning(f"Skipping invalid audio file: {ap}: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ final_audio = CompositeAudioClip(audio_clips) if audio_clips else None
34
+ final_video = concatenate_videoclips(video_clips, method="compose")
35
+
36
+ if final_audio is not None:
37
+ final_video = final_video.set_audio(final_audio)
38
+
39
+ final_video.write_videofile(output_path, codec="libx264", audio_codec="aac")
40
 
41
+ # Cleanup
42
+ final_video.close()
43
+ for vc in video_clips:
44
+ vc.close()
45
+ for ac in audio_clips:
46
+ ac.close()
47
 
48
  app = FastAPI()
49
 
50
  @app.post("/merge")
51
  async def merge_endpoint(
52
+ zip_file: UploadFile = File(...),
53
  orig_vol: float = Form(1.0),
54
  music_vol: float = Form(0.5),
55
  ):
56
  temp_dir = tempfile.mkdtemp()
57
  try:
58
+ # Save uploaded ZIP
59
+ zip_path = os.path.join(temp_dir, zip_file.filename)
60
+ with open(zip_path, "wb") as f:
61
+ f.write(await zip_file.read())
62
+
63
+ # Extract ZIP
64
+ extract_dir = os.path.join(temp_dir, "extracted")
65
+ os.makedirs(extract_dir, exist_ok=True)
66
+
67
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
68
+ zip_ref.extractall(extract_dir)
69
+
70
+ # Collect files
71
+ files = os.listdir(extract_dir)
72
+ video_files = [
73
+ os.path.join(extract_dir, f)
74
+ for f in files
75
+ if f.lower().endswith(".mp4")
76
+ ]
77
+ audio_files = [
78
+ os.path.join(extract_dir, f)
79
+ for f in files
80
+ if f.lower().endswith((".mp3", ".wav", ".aac", ".m4a", ".ogg"))
81
+ ]
82
+
83
+ if len(video_files) == 0 and len(audio_files) == 0:
84
+ return {"error": "No valid video or audio files found in ZIP."}
85
+
86
+ # Output path
87
+ output_path = os.path.join(temp_dir, "merged_output.mp4")
88
+
89
+ # Merge
90
+ merge_videos_and_audios(video_files, audio_files, output_path)
91
+
92
+ # Return result
93
+ return FileResponse(
94
+ output_path,
95
+ media_type="video/mp4",
96
+ filename="merged_output.mp4"
97
+ )
98
 
99
+ except Exception as e:
100
+ error_msg = f"Error: {str(e)}\n{traceback.format_exc()}"
101
+ logger.error(error_msg)
102
+ return {"error": error_msg}
 
 
 
 
 
 
 
 
 
 
 
103
 
104
  finally:
105
+ shutil.rmtree(temp_dir)
 
 
 
 
 
106
 
107
+ # Optional: log public URL
108
  def log_api_url():
109
  url = os.getenv("SPACE_PUBLIC_URL")
110
  if url: