Ryanus commited on
Commit
bb17dc0
·
verified ·
1 Parent(s): c423fd6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -15
app.py CHANGED
@@ -7,7 +7,8 @@ import shutil
7
  import zipfile
8
  from datetime import datetime
9
  import json
10
- import concurrent.futures # 新增:用于并行处理
 
11
 
12
  # 储存目录设置
13
  STORAGE_DIR = os.path.expanduser("~/video_storage")
@@ -216,7 +217,7 @@ def ffmpeg_cut_video(input_path, start_time, duration, output_path):
216
  """[优化] 快速的视频切割,使用 superfast 预设"""
217
  command = [
218
  'ffmpeg', '-i', input_path, '-ss', str(start_time), '-t', str(duration),
219
- '-c:v', 'libx264', '-preset', 'superfast', '-crf', '28', # 修改:更快的编码
220
  '-c:a', 'aac', '-b:a', '128k', '-avoid_negative_ts', 'make_zero', '-y', output_path
221
  ]
222
  result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -231,7 +232,7 @@ def ffmpeg_resize_video(input_path, output_path, target_ratio):
231
 
232
  command = [
233
  'ffmpeg', '-i', input_path, '-vf', filter_complex,
234
- '-c:v', 'libx264', '-preset', 'superfast', '-crf', '28', '-c:a', 'copy', '-y', output_path # 修改:更快的编码
235
  ]
236
  result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
237
  return result.returncode == 0 and os.path.exists(output_path)
@@ -292,78 +293,100 @@ def process_single_video(video_file, clip_duration, temp_dir):
292
  return clips
293
 
294
  def process_videos_with_storage(video_files, clip_duration, num_output_videos, target_ratio):
295
- """带储存功能的视频处理 [优化版:并行切割 + 批量更新]"""
296
  if not video_files:
297
  return "❌ 请上传视频文件", None, "", ""
298
 
 
299
  temp_dir = tempfile.mkdtemp()
300
 
301
  try:
 
 
 
302
  all_clips = []
303
 
304
  # --- [优化] 使用线程池并行处理每个视频文件 ---
 
305
  with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 1)) as executor:
306
- # 提交所有任务
307
  future_to_video = {
308
  executor.submit(process_single_video, vf, clip_duration, temp_dir): vf
309
  for vf in video_files
310
  }
311
 
312
- # 收集所有切片
313
  for future in concurrent.futures.as_completed(future_to_video):
 
314
  try:
315
  video_clips = future.result()
316
  all_clips.extend(video_clips)
 
 
317
  except Exception as exc:
318
  video_file = future_to_video[future]
319
- print(f'处理视频 {video_file.name} 时发生异常: {exc}')
 
320
  # --- 并行处理结束 ---
 
321
 
322
  if not all_clips:
323
  return "❌ 切割失败,请检查视频文件", None, "", ""
324
-
325
  random.shuffle(all_clips)
326
  clips_per_video = max(1, len(all_clips) // num_output_videos)
327
  output_files = []
328
- stored_files = [] # 用于记录成功保存的文件名
329
-
 
330
  for i in range(num_output_videos):
331
  start_idx = i * clips_per_video
332
  end_idx = len(all_clips) if i == num_output_videos - 1 else (start_idx + clips_per_video)
333
  selected_clips = all_clips[start_idx:end_idx]
334
 
335
  if not selected_clips:
 
336
  continue
337
 
338
  temp_merged = os.path.join(temp_dir, f"merged_{i+1}.mp4")
 
339
  if not concat_videos(selected_clips, temp_merged):
 
340
  continue
341
 
342
  timestamp = datetime.now().strftime('%H%M%S')
343
  final_output = os.path.join(temp_dir, f"混剪视频_{target_ratio.replace(':', 'x')}_{i+1}_{timestamp}.mp4")
 
344
 
345
  if ffmpeg_resize_video(temp_merged, final_output, target_ratio):
346
  output_files.append(final_output)
347
  stored_path = save_to_storage(final_output)
348
  if stored_path:
349
  stored_files.append(os.path.basename(stored_path))
350
-
 
 
 
 
 
351
  # --- [优化] 所有文件保存后,统一更新一次配置 ---
352
- if stored_files: # 只有当有文件被成功储存时才更新
353
  update_storage_config()
354
- # --- 优化结束 ---
355
-
356
  if not output_files:
357
  return "❌ 生成混剪视频失败", None, "", ""
358
-
 
359
  package_dir = tempfile.mkdtemp()
360
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
361
  zip_path = os.path.join(package_dir, f"混剪视频包_{target_ratio.replace(':', 'x')}_{timestamp}.zip")
362
 
 
363
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
364
  for video_file in output_files:
365
  arcname = os.path.basename(video_file)
366
  zipf.write(video_file, arcname)
 
367
 
368
  readme = f"""# 混剪视频包
369
 
@@ -391,6 +414,12 @@ def process_videos_with_storage(video_files, clip_duration, num_output_videos, t
391
  total_size = os.path.getsize(zip_path) / (1024 * 1024)
392
  platform_info = "📱 短视频平台" if target_ratio == '9:16' else "🖥️ 长视频平台"
393
 
 
 
 
 
 
 
394
  success_msg = f"""✅ 混剪完成并已储存!
395
 
396
  📊 **生成统计:**
@@ -437,10 +466,12 @@ def process_videos_with_storage(video_files, clip_duration, num_output_videos, t
437
  return success_msg, zip_path, details, storage_info
438
 
439
  except Exception as e:
 
440
  return f"❌ 处理失败: {str(e)}", None, "", ""
441
 
442
  finally:
443
  shutil.rmtree(temp_dir, ignore_errors=True)
 
444
 
445
  def refresh_storage_display():
446
  """刷新储存空间显示"""
 
7
  import zipfile
8
  from datetime import datetime
9
  import json
10
+ import concurrent.futures
11
+ import time
12
 
13
  # 储存目录设置
14
  STORAGE_DIR = os.path.expanduser("~/video_storage")
 
217
  """[优化] 快速的视频切割,使用 superfast 预设"""
218
  command = [
219
  'ffmpeg', '-i', input_path, '-ss', str(start_time), '-t', str(duration),
220
+ '-c:v', 'libx264', '-preset', 'superfast', '-crf', '28',
221
  '-c:a', 'aac', '-b:a', '128k', '-avoid_negative_ts', 'make_zero', '-y', output_path
222
  ]
223
  result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
232
 
233
  command = [
234
  'ffmpeg', '-i', input_path, '-vf', filter_complex,
235
+ '-c:v', 'libx264', '-preset', 'superfast', '-crf', '28', '-c:a', 'copy', '-y', output_path
236
  ]
237
  result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
238
  return result.returncode == 0 and os.path.exists(output_path)
 
293
  return clips
294
 
295
  def process_videos_with_storage(video_files, clip_duration, num_output_videos, target_ratio):
296
+ """带储存功能的视频处理 [优化版:并行切割 + 批量更新 + 进度日志]"""
297
  if not video_files:
298
  return "❌ 请上传视频文件", None, "", ""
299
 
300
+ start_time = time.time() # ✅ 记录开始时间
301
  temp_dir = tempfile.mkdtemp()
302
 
303
  try:
304
+ print(f"🔍 开始处理 {len(video_files)} 个视频文件...")
305
+ print(f"⏱️ 切片时长: {clip_duration} 秒 | 生成数量: {num_output_videos} 个 | 比例: {target_ratio}")
306
+
307
  all_clips = []
308
 
309
  # --- [优化] 使用线程池并行处理每个视频文件 ---
310
+ print(f"🚀 启动并行切片({min(4, os.cpu_count() or 1)} 线程)...")
311
  with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 1)) as executor:
 
312
  future_to_video = {
313
  executor.submit(process_single_video, vf, clip_duration, temp_dir): vf
314
  for vf in video_files
315
  }
316
 
317
+ completed = 0
318
  for future in concurrent.futures.as_completed(future_to_video):
319
+ video_file = future_to_video[future]
320
  try:
321
  video_clips = future.result()
322
  all_clips.extend(video_clips)
323
+ completed += 1
324
+ print(f"✅ 已完成切片: {completed}/{len(video_files)} | 文件: {os.path.basename(video_file.name)} | 切片数: {len(video_clips)}")
325
  except Exception as exc:
326
  video_file = future_to_video[future]
327
+ print(f"❌ 切片失败: {os.path.basename(video_file.name)} - {exc}")
328
+
329
  # --- 并行处理结束 ---
330
+ print(f"📊 所有视频切片完成,共生成 {len(all_clips)} 个片段")
331
 
332
  if not all_clips:
333
  return "❌ 切割失败,请检查视频文件", None, "", ""
334
+
335
  random.shuffle(all_clips)
336
  clips_per_video = max(1, len(all_clips) // num_output_videos)
337
  output_files = []
338
+ stored_files = []
339
+
340
+ print(f"🎬 开始合并生成 {num_output_videos} 个混剪视频...")
341
  for i in range(num_output_videos):
342
  start_idx = i * clips_per_video
343
  end_idx = len(all_clips) if i == num_output_videos - 1 else (start_idx + clips_per_video)
344
  selected_clips = all_clips[start_idx:end_idx]
345
 
346
  if not selected_clips:
347
+ print(f"⚠️ 无足够片段生成第 {i+1} 个视频,跳过")
348
  continue
349
 
350
  temp_merged = os.path.join(temp_dir, f"merged_{i+1}.mp4")
351
+ print(f"🔗 正在合并 {len(selected_clips)} 个片段 → {temp_merged}...")
352
  if not concat_videos(selected_clips, temp_merged):
353
+ print(f"❌ 合并失败: 第 {i+1} 个视频")
354
  continue
355
 
356
  timestamp = datetime.now().strftime('%H%M%S')
357
  final_output = os.path.join(temp_dir, f"混剪视频_{target_ratio.replace(':', 'x')}_{i+1}_{timestamp}.mp4")
358
+ print(f"🎬 正在调整比例 {target_ratio} → {final_output}...")
359
 
360
  if ffmpeg_resize_video(temp_merged, final_output, target_ratio):
361
  output_files.append(final_output)
362
  stored_path = save_to_storage(final_output)
363
  if stored_path:
364
  stored_files.append(os.path.basename(stored_path))
365
+ print(f"💾 已保存混剪视频: {os.path.basename(stored_path)}")
366
+ else:
367
+ print(f"❌ 保存失败: {final_output}")
368
+ else:
369
+ print(f"❌ 比例调整失败: 第 {i+1} 个视频")
370
+
371
  # --- [优化] 所有文件保存后,统一更新一次配置 ---
372
+ if stored_files:
373
  update_storage_config()
374
+ print(f"✅ 已统一更新储存配置,共保存 {len(stored_files)} 个视频文件")
375
+
376
  if not output_files:
377
  return "❌ 生成混剪视频失败", None, "", ""
378
+
379
+ # --- 打包下载 ---
380
  package_dir = tempfile.mkdtemp()
381
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
382
  zip_path = os.path.join(package_dir, f"混剪视频包_{target_ratio.replace(':', 'x')}_{timestamp}.zip")
383
 
384
+ print(f"📦 正在打包 {len(output_files)} 个视频文件为 ZIP...")
385
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
386
  for video_file in output_files:
387
  arcname = os.path.basename(video_file)
388
  zipf.write(video_file, arcname)
389
+ print(f" ➤ 已添加: {arcname}")
390
 
391
  readme = f"""# 混剪视频包
392
 
 
414
  total_size = os.path.getsize(zip_path) / (1024 * 1024)
415
  platform_info = "📱 短视频平台" if target_ratio == '9:16' else "🖥️ 长视频平台"
416
 
417
+ end_time = time.time() # ✅ 计算耗时
418
+ elapsed = end_time - start_time
419
+ print(f"🎉 混剪完成!总耗时: {elapsed:.1f} 秒")
420
+ print(f"📥 下载包大小: {total_size:.1f}MB")
421
+ print(f"📁 已保存文件: {len(stored_files)} 个")
422
+
423
  success_msg = f"""✅ 混剪完成并已储存!
424
 
425
  📊 **生成统计:**
 
466
  return success_msg, zip_path, details, storage_info
467
 
468
  except Exception as e:
469
+ print(f"❌ 处理失败: {str(e)}")
470
  return f"❌ 处理失败: {str(e)}", None, "", ""
471
 
472
  finally:
473
  shutil.rmtree(temp_dir, ignore_errors=True)
474
+ print("🧹 临时文件夹已清理")
475
 
476
  def refresh_storage_display():
477
  """刷新储存空间显示"""