Ezmary commited on
Commit
c9e7bc1
·
verified ·
1 Parent(s): e794064

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +21 -30
app.py CHANGED
@@ -139,12 +139,11 @@ def apply_watermark(input_video, watermark_img, output_video):
139
  f"if(lt(mod(t,15),12), (H-h-10) - {speed}*mod(t,3), "
140
  "(H-h)/2 + 20*cos(t)))))"
141
  )
142
- # استفاده از re-encode برای اطمینان از سینک بودن واترمارک با فریم‌ها
143
  subprocess.run([
144
  "ffmpeg", "-y", "-i", input_video, "-i", watermark_img,
145
  "-filter_complex", f"[0:v][1:v]overlay=x='{expr_x}':y='{expr_y}'",
146
  "-c:a", "copy",
147
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", "24", # تنظیم کیفیت مناسب
148
  output_video
149
  ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
150
  return True
@@ -155,12 +154,6 @@ def apply_watermark(input_video, watermark_img, output_video):
155
  # --- توابع پردازش هوشمند صدا (برش دقیق) ---
156
 
157
  def smart_split_audio(file_path, job_id):
158
- """
159
- الگوریتم برش دقیق:
160
- 1. اولویت: بازه ۱۴ تا ۱۹ ثانیه.
161
- 2. پشتیبان: بازه ۹ تا ۱۴ ثانیه (برای جلوگیری از برش وسط کلمه).
162
- 3. آخر خط: برش سر ۱۹ ثانیه.
163
- """
164
  try:
165
  audio = AudioSegment.from_file(file_path)
166
  total_len = len(audio)
@@ -179,8 +172,6 @@ def smart_split_audio(file_path, job_id):
179
  cut_point = 0
180
  found_cut = False
181
 
182
- # جستجو در بازه ۱۴ تا ۱۹ (ایده‌آل)
183
- # از SILENCE_MIN_LEN 250 استفاده میکنیم تا مکث های کوتاه تر هم پیدا شن
184
  search_start = start + 14000
185
  search_end = min(start + MAX_CUT_TIME, total_len)
186
 
@@ -189,13 +180,11 @@ def smart_split_audio(file_path, job_id):
189
  silences = detect_silence(chunk_search, min_silence_len=SILENCE_MIN_LEN, silence_thresh=SILENCE_THRESH)
190
 
191
  if silences:
192
- # وسط سکوت برش بزن
193
  s = silences[0]
194
  mid = s[0] + (s[1] - s[0]) // 2
195
  cut_point = search_start + mid
196
  found_cut = True
197
 
198
- # اگر در ۱۴-۱۹ پیدا نشد، در بازه ۹ تا ۱۴ بگرد (برای حفظ کیفیت بهتر از طولانی بودن است)
199
  if not found_cut:
200
  search_start_safe = start + 9000
201
  search_end_safe = start + 14000
@@ -209,7 +198,6 @@ def smart_split_audio(file_path, job_id):
209
  cut_point = search_start_safe + mid
210
  found_cut = True
211
 
212
- # اگر هیچ جا سکوت نبود (اجباری)
213
  if not found_cut:
214
  cut_point = start + MAX_CUT_TIME
215
 
@@ -240,9 +228,6 @@ def convert_audio_to_wav(input_path, output_path):
240
  except: return False
241
 
242
  def merge_videos_smart(video_map, total_parts, output_path):
243
- """
244
- ادغام ویدیوها با Re-encode (بازسازی) برای جلوگیری از حذف فریم و کسر زمان
245
- """
246
  try:
247
  videos = []
248
  for i in range(total_parts):
@@ -260,17 +245,13 @@ def merge_videos_smart(video_map, total_parts, output_path):
260
  for v in videos:
261
  f.write(f"file '{os.path.abspath(v)}'\n")
262
 
263
- # تغییر حیاتی: استفاده از concat filter بجای concat demuxer
264
- # روش قبلی (-c copy) باعث حذف فریم‌ها در نقاط اتصال می‌شد.
265
- # این روش ویدیو را دوباره رندر می‌کند تا فریم‌ها دقیقاً پشت هم قرار بگیرند.
266
- # از ultrafast استفاده می‌کنیم تا سرعت بالا بماند.
267
  subprocess.run([
268
  "ffmpeg", "-y",
269
  "-f", "concat",
270
  "-safe", "0",
271
  "-i", "list.txt",
272
- "-c:v", "libx264", "-preset", "ultrafast", "-crf", "24", # بازسازی تصویر
273
- "-c:a", "aac", # بازسازی صدا
274
  output_path
275
  ], check=True)
276
  return True
@@ -278,12 +259,6 @@ def merge_videos_smart(video_map, total_parts, output_path):
278
  logger.error(f"Merge Error: {e}")
279
  return False
280
 
281
- def add_audio_to_video(video_path, audio_path, output_path):
282
- try:
283
- subprocess.run(["ffmpeg", "-y", "-i", video_path, "-i", audio_path, "-c:v", "copy", "-c:a", "aac", "-map", "0:v:0", "-map", "1:a:0", "-shortest", output_path], check=True)
284
- return True
285
- except: return False
286
-
287
  # --- توزیع کار ---
288
 
289
  async def dispatch_all_parallel(job_id, img_path, audio_files, resolution):
@@ -384,9 +359,25 @@ async def create_job(background_tasks: BackgroundTasks, image: UploadFile = File
384
  if not convert_audio_to_wav(temp_audio, final_audio):
385
  return JSONResponse(status_code=400, content={"error": "Audio conversion failed"})
386
 
 
387
  audio_parts = smart_split_audio(final_audio, job_id)
388
- total_parts = len(audio_parts)
389
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  parts_status_init = {str(i): "PENDING" for i in range(total_parts)}
391
 
392
  db = SessionLocal()
@@ -395,7 +386,7 @@ async def create_job(background_tasks: BackgroundTasks, image: UploadFile = File
395
  original_image_path=img_path, original_audio_path=final_audio,
396
  total_parts=total_parts, parts_status=parts_status_init,
397
  audio_parts=audio_parts, video_parts={},
398
- message=f"شروع پردازش همزمان {total_parts} قسمت...",
399
  last_activity=datetime.utcnow()
400
  )
401
  db.add(new_job)
 
139
  f"if(lt(mod(t,15),12), (H-h-10) - {speed}*mod(t,3), "
140
  "(H-h)/2 + 20*cos(t)))))"
141
  )
 
142
  subprocess.run([
143
  "ffmpeg", "-y", "-i", input_video, "-i", watermark_img,
144
  "-filter_complex", f"[0:v][1:v]overlay=x='{expr_x}':y='{expr_y}'",
145
  "-c:a", "copy",
146
+ "-c:v", "libx264", "-preset", "ultrafast", "-crf", "24",
147
  output_video
148
  ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
149
  return True
 
154
  # --- توابع پردازش هوشمند صدا (برش دقیق) ---
155
 
156
  def smart_split_audio(file_path, job_id):
 
 
 
 
 
 
157
  try:
158
  audio = AudioSegment.from_file(file_path)
159
  total_len = len(audio)
 
172
  cut_point = 0
173
  found_cut = False
174
 
 
 
175
  search_start = start + 14000
176
  search_end = min(start + MAX_CUT_TIME, total_len)
177
 
 
180
  silences = detect_silence(chunk_search, min_silence_len=SILENCE_MIN_LEN, silence_thresh=SILENCE_THRESH)
181
 
182
  if silences:
 
183
  s = silences[0]
184
  mid = s[0] + (s[1] - s[0]) // 2
185
  cut_point = search_start + mid
186
  found_cut = True
187
 
 
188
  if not found_cut:
189
  search_start_safe = start + 9000
190
  search_end_safe = start + 14000
 
198
  cut_point = search_start_safe + mid
199
  found_cut = True
200
 
 
201
  if not found_cut:
202
  cut_point = start + MAX_CUT_TIME
203
 
 
228
  except: return False
229
 
230
  def merge_videos_smart(video_map, total_parts, output_path):
 
 
 
231
  try:
232
  videos = []
233
  for i in range(total_parts):
 
245
  for v in videos:
246
  f.write(f"file '{os.path.abspath(v)}'\n")
247
 
 
 
 
 
248
  subprocess.run([
249
  "ffmpeg", "-y",
250
  "-f", "concat",
251
  "-safe", "0",
252
  "-i", "list.txt",
253
+ "-c:v", "libx264", "-preset", "ultrafast", "-crf", "24",
254
+ "-c:a", "aac",
255
  output_path
256
  ], check=True)
257
  return True
 
259
  logger.error(f"Merge Error: {e}")
260
  return False
261
 
 
 
 
 
 
 
262
  # --- توزیع کار ---
263
 
264
  async def dispatch_all_parallel(job_id, img_path, audio_files, resolution):
 
359
  if not convert_audio_to_wav(temp_audio, final_audio):
360
  return JSONResponse(status_code=400, content={"error": "Audio conversion failed"})
361
 
362
+ # برش صدا
363
  audio_parts = smart_split_audio(final_audio, job_id)
 
364
 
365
+ # --- منطق جدید برای کاربران رایگان ---
366
+ # اگر کاربر رایگان است و تعداد پارت‌ها بیشتر از ۱ است، فقط پارت اول را نگه دار
367
+ if not is_premium and len(audio_parts) > 1:
368
+ # حذف فایل‌های اضافی از حافظه
369
+ for part in audio_parts[1:]:
370
+ try:
371
+ os.remove(part)
372
+ except:
373
+ pass
374
+ # فقط پارت اول (که زیر 19 ثانیه است) را نگه دار
375
+ audio_parts = [audio_parts[0]]
376
+ initial_msg = "شروع پردازش (محدود به ۱۹ ثانیه نسخه رایگان)..."
377
+ else:
378
+ initial_msg = f"شروع پردازش همزمان {len(audio_parts)} قسمت..."
379
+
380
+ total_parts = len(audio_parts)
381
  parts_status_init = {str(i): "PENDING" for i in range(total_parts)}
382
 
383
  db = SessionLocal()
 
386
  original_image_path=img_path, original_audio_path=final_audio,
387
  total_parts=total_parts, parts_status=parts_status_init,
388
  audio_parts=audio_parts, video_parts={},
389
+ message=initial_msg,
390
  last_activity=datetime.utcnow()
391
  )
392
  db.add(new_job)