Ryanus commited on
Commit
d4c1a45
·
verified ·
1 Parent(s): b0ceae3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -87
app.py CHANGED
@@ -1,92 +1,118 @@
1
  import os
2
- import pickle
3
- from googleapiclient.discovery import build
4
- from googleapiclient.http import MediaFileUpload
5
- from google_auth_oauthlib.flow import InstalledAppFlow
6
- from google.auth.transport.requests import Request
7
-
8
- CLIENT_SECRETS_FILE = 'client_secrets.json'
9
- CREDENTIALS_FILE = 'youtube_token.pickle'
10
- SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
11
-
12
- def authenticate_youtube():
13
- creds = None
14
- if os.path.exists(CREDENTIALS_FILE):
15
- with open(CREDENTIALS_FILE, 'rb') as token:
16
- creds = pickle.load(token)
17
- if not creds or not creds.valid:
18
- if creds and creds.expired and creds.refresh_token:
19
- creds.refresh(Request())
20
- else:
21
- flow = InstalledAppFlow.from_client_secrets_file(
22
- CLIENT_SECRETS_FILE, SCOPES)
23
- # 不自动打开浏览器,手动复制链接访问授权
24
- creds = flow.run_local_server(port=0, open_browser=False)
25
- print("请复制以上链接,在浏览器中打开并完成授权,授权成功后程序将继续运行。")
26
- with open(CREDENTIALS_FILE, 'wb') as token:
27
- pickle.dump(creds, token)
28
- youtube = build('youtube', 'v3', credentials=creds)
29
- return youtube
30
-
31
- def upload_video(youtube, video_path, title, description, tags=None, privacy_status="private"):
32
- if not os.path.exists(video_path):
33
- print(f"错误:找不到视频文件 {video_path}")
34
- return None
35
-
36
- body = {
37
- 'snippet': {
38
- 'title': title,
39
- 'description': description,
40
- 'tags': tags or [],
41
- 'categoryId': '22' # People & Blogs
42
- },
43
- 'status': {
44
- 'privacyStatus': privacy_status,
45
- 'selfDeclaredMadeForKids': False
46
- }
47
- }
48
-
49
- media = MediaFileUpload(video_path, chunksize=-1, resumable=True, mimetype='video/*')
50
- request = youtube.videos().insert(
51
- part=','.join(body.keys()),
52
- body=body,
53
- media_body=media
54
- )
55
- response = request.execute()
56
-
57
- print(f"上传成功!视频链接:https://www.youtube.com/watch?v={response['id']}")
58
- return response['id']
59
 
60
- def main():
61
- youtube = authenticate_youtube()
62
-
63
- # 这里填写你要上传的视频文件路径和信息
64
- videos_to_upload = [
65
- {
66
- 'path': 'your_video_1.mp4',
67
- 'title': '视频标题1',
68
- 'description': '这是视频描述1',
69
- 'tags': ['示例', '测试'],
70
- 'privacy_status': 'private'
71
- },
72
- {
73
- 'path': 'your_video_2.mp4',
74
- 'title': '视频标题2',
75
- 'description': '这是视频描述2',
76
- 'tags': ['样例', '上传'],
77
- 'privacy_status': 'unlisted'
78
- }
79
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
- for video in videos_to_upload:
82
- upload_video(
83
- youtube,
84
- video['path'],
85
- video['title'],
86
- video['description'],
87
- video['tags'],
88
- video['privacy_status']
89
- )
90
-
91
- if __name__ == '__main__':
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  main()
 
1
  import os
2
+ import gradio as gr
3
+ import tempfile
4
+ import random
5
+ import subprocess
6
+ from datetime import datetime
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ def ffmpeg_cut_video(input_path, start_time, duration, output_path):
9
+ """调用ffmpeg剪辑视频片段"""
10
+ command = [
11
+ 'ffmpeg',
12
+ '-ss', str(start_time),
13
+ '-i', input_path,
14
+ '-t', str(duration),
15
+ '-c', 'copy',
16
+ '-y',
17
+ output_path
 
 
 
 
 
 
 
 
 
18
  ]
19
+ process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
20
+ return process.returncode == 0
21
+
22
+ def concat_videos_ffmpeg(file_list, output_path):
23
+ """调用ffmpeg合并多个视频,使用文件列表"""
24
+ list_file = tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt')
25
+ try:
26
+ for f in file_list:
27
+ list_file.write(f"file '{f.replace('\'', '\'\\\'\'' )}'\n")
28
+ list_file.close()
29
+
30
+ command = [
31
+ 'ffmpeg',
32
+ '-f', 'concat',
33
+ '-safe', '0',
34
+ '-i', list_file.name,
35
+ '-c', 'copy',
36
+ '-y',
37
+ output_path
38
+ ]
39
+ process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
40
+ return process.returncode == 0
41
+ finally:
42
+ os.unlink(list_file.name)
43
+
44
+ def process_videos(video_files, clip_duration=2, num_output_videos=3):
45
+ if not video_files or len(video_files) == 0:
46
+ return "❌ 请上传至少一个视频文件", []
47
+
48
+ temp_dir = tempfile.mkdtemp()
49
+ all_clips = []
50
+
51
+ try:
52
+ for idx, video_file in enumerate(video_files):
53
+ video_path = video_file.name
54
+ # 获取视频总时长
55
+ cmd_duration = [
56
+ 'ffprobe', '-v', 'error',
57
+ '-show_entries', 'format=duration',
58
+ '-of', 'default=noprint_wrappers=1:nokey=1',
59
+ video_path
60
+ ]
61
+ result = subprocess.run(cmd_duration, capture_output=True, text=True)
62
+ total_duration = float(result.stdout.strip())
63
+ # 按clip_duration分割视频
64
+ start = 0.0
65
+ count = 0
66
+ while start < total_duration:
67
+ duration = min(clip_duration, total_duration - start)
68
+ clip_path = os.path.join(temp_dir, f"clip_{idx}_{count}.mp4")
69
+ ok = ffmpeg_cut_video(video_path, start, duration, clip_path)
70
+ if not ok:
71
+ return f"❌ 视频剪辑失败: {video_path}", []
72
+ all_clips.append(clip_path)
73
+ start += duration
74
+ count += 1
75
+
76
+ # 随机打乱clip顺序
77
+ random.shuffle(all_clips)
78
+
79
+ # 计算每个输出视频包含的clip数量
80
+ clips_per_video = max(1, len(all_clips) // num_output_videos)
81
 
82
+ output_files = []
83
+
84
+ for i in range(num_output_videos):
85
+ start_idx = i * clips_per_video
86
+ end_idx = len(all_clips) if i == num_output_videos -1 else (start_idx + clips_per_video)
87
+ selected_clips = all_clips[start_idx:end_idx]
88
+ output_path = os.path.join(temp_dir, f"mixed_video_{i +1}.mp4")
89
+ ok = concat_videos_ffmpeg(selected_clips, output_path)
90
+ if not ok:
91
+ return "❌ 视频合并失败", []
92
+ output_files.append(output_path)
93
+
94
+ return f"成功生成 {len(output_files)} 个混剪视频", output_files
95
+
96
+ except Exception as e:
97
+ return f"❌ 处理异常: {str(e)}", []
98
+
99
+ def main():
100
+ with gr.Blocks() as demo:
101
+ gr.Markdown("## FFmpeg 自动剪辑混剪视频 (无需任何API)")
102
+ video_input = gr.File(file_types=[".mp4", ".mov", ".avi", ".mkv"], file_count="multiple", label="上传视频文件")
103
+ clip_duration = gr.Number(value=2, label="剪辑片段时长 (秒)", minimum=1, maximum=30)
104
+ num_output = gr.Number(value=3, label="输出混剪视频数量", minimum=1, maximum=10)
105
+ btn = gr.Button("开始剪辑")
106
+
107
+ status = gr.Textbox(label="剪辑状态", interactive=False, lines=4)
108
+ outputs = gr.File(file_count="multiple", label="下载混剪视频")
109
+
110
+ def process(video_files, clip_duration, num_output):
111
+ return process_videos(video_files, clip_duration, num_output)
112
+
113
+ btn.click(process, inputs=[video_input, clip_duration, num_output], outputs=[status, outputs])
114
+
115
+ demo.launch()
116
+
117
+ if __name__ == "__main__":
118
  main()