weepakistan commited on
Commit
41c2ec8
·
verified ·
1 Parent(s): 2e183b7

Upload 2 files

Browse files
Files changed (2) hide show
  1. app (1).py +246 -0
  2. requirements.txt +6 -0
app (1).py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ import shutil
4
+ import gradio as gr
5
+ import requests
6
+ import subprocess
7
+ import json
8
+ import yt_dlp
9
+ from PIL import Image
10
+ from io import BytesIO
11
+ from dotenv import load_dotenv
12
+
13
+ # Load environment variables
14
+ load_dotenv()
15
+
16
+ # Get API key and base URL from environment variables
17
+ API_KEY = os.getenv('Key')
18
+ BASE_URL = os.getenv('Base')
19
+
20
+ def get_movie_or_tv_details(title):
21
+ search_url = f'{BASE_URL}/search/multi'
22
+ params = {
23
+ 'api_key': API_KEY,
24
+ 'query': title
25
+ }
26
+ response = requests.get(search_url, params=params)
27
+ response.raise_for_status()
28
+ results = response.json().get('results')
29
+ if not results:
30
+ raise ValueError(f"No results found for title: {title}")
31
+
32
+ details = results[0]
33
+ if details['media_type'] == 'movie':
34
+ release_date = details.get('release_date', '')
35
+ elif details['media_type'] == 'tv':
36
+ release_date = details.get('first_air_date', '')
37
+ else:
38
+ raise ValueError("Unsupported media type")
39
+
40
+ release_year = release_date.split('-')[0] if release_date else 'Unknown'
41
+ return details, release_year
42
+
43
+ def get_images_url(media_type, media_id):
44
+ if media_type == 'movie':
45
+ images_url = f'{BASE_URL}/movie/{media_id}/images'
46
+ elif media_type == 'tv':
47
+ images_url = f'{BASE_URL}/tv/{media_id}/images'
48
+ else:
49
+ raise ValueError("Unsupported media type")
50
+ params = {'api_key': API_KEY}
51
+ response = requests.get(images_url, params=params)
52
+ response.raise_for_status()
53
+ return response.json()
54
+
55
+ def save_summary_and_images(title, summary, images, media_type, year):
56
+ prefix = 'Movie' if media_type == 'movie' else 'TV Show'
57
+ if not os.path.exists('images'):
58
+ os.makedirs('images')
59
+
60
+ with open(f"{prefix} {title} {year}.txt", 'w', encoding='utf-8') as file:
61
+ file.write(summary)
62
+
63
+ for idx, image in enumerate(images[:12]):
64
+ image_url = f"https://image.tmdb.org/t/p/original{image['file_path']}"
65
+ response = requests.get(image_url)
66
+ response.raise_for_status()
67
+ img = Image.open(BytesIO(response.content))
68
+ img = img.resize((1080, 1920), Image.LANCZOS)
69
+ img.save(f"images/{prefix} {title} {idx + 1} ({year}).jpg")
70
+
71
+ def generate_voiceover(text, output_file):
72
+ edge_tts_command = [
73
+ "edge-tts",
74
+ "--text", text,
75
+ "--write-media", output_file
76
+ ]
77
+ try:
78
+ subprocess.run(edge_tts_command, check=True)
79
+ print(f"Generated voiceover: {output_file}")
80
+ except subprocess.CalledProcessError as e:
81
+ print(f"Failed to generate voiceover: {e}")
82
+
83
+ def process_text_files(prefix, suffix):
84
+ current_dir = os.getcwd()
85
+ txt_files = [file for file in os.listdir(current_dir) if file.endswith('.txt')]
86
+
87
+ for txt_file in txt_files:
88
+ file_path = os.path.join(current_dir, txt_file)
89
+ file_name = os.path.splitext(txt_file)[0]
90
+
91
+ with open(file_path, 'r', encoding='utf-8') as file:
92
+ text = file.read().strip()
93
+
94
+ processed_text = f"{prefix} {file_name}: {text} {suffix}"
95
+ audio_file_path = f"{file_name}.mp3"
96
+
97
+ generate_voiceover(processed_text, audio_file_path)
98
+ print(f"Processed File: {txt_file}")
99
+ print("Exported Audio:", audio_file_path)
100
+ print()
101
+
102
+ def make_slideshow(images_folder, audio_file):
103
+ image_files = sorted([img for img in os.listdir(images_folder) if img.endswith((".jpg", ".png"))])
104
+ images = [os.path.join(images_folder, img) for img in image_files]
105
+
106
+ audio_duration = float(subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', audio_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout)
107
+
108
+ commands = []
109
+ for image in images:
110
+ commands.append(f"file '{image}'")
111
+ commands.append(f"duration {audio_duration / len(images)}")
112
+ with open('filelist.txt', 'w') as filelist:
113
+ filelist.write("\n".join(commands))
114
+
115
+ base_name = os.path.splitext(os.path.basename(audio_file))[0]
116
+ output_file = f'{base_name}.mp4'
117
+
118
+ subprocess.run(['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', 'filelist.txt', '-i', audio_file, '-c:v', 'libx264', '-pix_fmt', 'yuv420p', output_file])
119
+
120
+ os.remove('filelist.txt')
121
+
122
+ def download_music(search_query):
123
+ ydl_opts = {
124
+ 'format': 'bestaudio/best',
125
+ 'postprocessors': [{
126
+ 'key': 'FFmpegExtractAudio',
127
+ 'preferredcodec': 'mp3',
128
+ 'preferredquality': '192',
129
+ }],
130
+ 'outtmpl': 'background_music.%(ext)s'
131
+ }
132
+
133
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
134
+ try:
135
+ ydl.download([f"ytsearch1:{search_query}"])
136
+ return "background_music.mp3"
137
+ except:
138
+ print("Error downloading music. Please check your internet connection or try a different search query.")
139
+ return None
140
+
141
+ def trim_audio(audio_path, target_duration):
142
+ output_path = "trimmed_background_music.mp3"
143
+ cmd = ['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams', audio_path]
144
+ result = subprocess.run(cmd, capture_output=True, text=True)
145
+ data = json.loads(result.stdout)
146
+ audio_duration = float(data['format']['duration'])
147
+
148
+ if audio_duration > target_duration:
149
+ start_time = (audio_duration - target_duration) / 2
150
+ cmd = ['ffmpeg', '-i', audio_path, '-ss', str(start_time), '-t', str(target_duration), '-c', 'copy', output_path]
151
+ subprocess.run(cmd)
152
+ return output_path
153
+ else:
154
+ return audio_path
155
+
156
+ def combine_audio_with_video(video_path, bg_music_path, bg_music_volume=0.3):
157
+ temp_output = "temp_output.mp4"
158
+ cmd = [
159
+ 'ffmpeg',
160
+ '-i', video_path,
161
+ '-i', bg_music_path,
162
+ '-filter_complex',
163
+ f'[1:a]volume={bg_music_volume}[bg];[0:a][bg]amix=inputs=2:duration=longest',
164
+ '-c:v', 'copy',
165
+ '-c:a', 'aac',
166
+ '-b:a', '192k',
167
+ temp_output
168
+ ]
169
+ subprocess.run(cmd)
170
+
171
+ os.remove(video_path)
172
+ os.rename(temp_output, video_path)
173
+
174
+ def main(title):
175
+ # Create sessions directory if it doesn't exist
176
+ sessions_dir = "sessions"
177
+ os.makedirs(sessions_dir, exist_ok=True)
178
+
179
+ # Create session directory
180
+ session_dir = os.path.join(sessions_dir, next(tempfile._get_candidate_names()))
181
+ os.makedirs(session_dir, exist_ok=True)
182
+ os.chdir(session_dir)
183
+
184
+ try:
185
+ details, release_year = get_movie_or_tv_details(title)
186
+ media_type = details['media_type']
187
+ media_id = details['id']
188
+ summary = details.get('overview', 'No summary available.')
189
+ images_data = get_images_url(media_type, media_id)
190
+ images = images_data.get('backdrops', [])
191
+
192
+ save_summary_and_images(title, summary, images, media_type, release_year)
193
+
194
+ prefix_text = "Here is the summary of the"
195
+ suffix_text = "Have you watched it? Do tell us in the comments section."
196
+ process_text_files(prefix_text, suffix_text)
197
+
198
+ audio_file = next((f for f in os.listdir('.') if f.lower().endswith('.mp3')), None)
199
+ if audio_file:
200
+ make_slideshow('images', audio_file)
201
+
202
+ output_video_file = None
203
+ mp4_files = [f for f in os.listdir() if f.endswith('.mp4')]
204
+ for video_file in mp4_files:
205
+ video_duration = float(subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', video_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout)
206
+
207
+ search_query = f"{os.path.splitext(video_file)[0]} background music"
208
+ music_file = download_music(search_query)
209
+
210
+ if music_file:
211
+ trimmed_music = trim_audio(music_file, video_duration)
212
+ combine_audio_with_video(video_file, trimmed_music)
213
+
214
+ if os.path.exists(music_file):
215
+ os.remove(music_file)
216
+ if os.path.exists(trimmed_music) and trimmed_music != music_file:
217
+ os.remove(trimmed_music)
218
+
219
+ output_video_file = video_file
220
+
221
+ # Move the final video to the main directory
222
+ if output_video_file:
223
+ final_video_path = os.path.join("..", output_video_file)
224
+ shutil.move(output_video_file, final_video_path)
225
+ return gr.File(final_video_path)
226
+ else:
227
+ return "Error creating video."
228
+
229
+ except Exception as e:
230
+ return f"An error occurred: {e}"
231
+
232
+ finally:
233
+ # Ensure session_dir exists before deleting
234
+ if os.path.exists(session_dir):
235
+ shutil.rmtree(session_dir)
236
+
237
+ with gr.Blocks() as iface:
238
+ gr.Interface(
239
+ fn=main,
240
+ inputs=gr.Textbox(label="Enter the movie or TV show title:"),
241
+ outputs=gr.Video(label="Output Video"),
242
+ title="Movie/TV Show Video Summary Generator",
243
+ description="Enter a movie or TV show title to generate a summary video with voiceover and background music."
244
+ )
245
+
246
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ requests
2
+ Pillow
3
+ yt-dlp
4
+ gradio
5
+ edge-tts
6
+ python-dotenv