Update app.py
Browse files
app.py
CHANGED
@@ -20,237 +20,6 @@ from PIL import Image
|
|
20 |
api_key = "268976:66f4f58a2a905"
|
21 |
|
22 |
|
23 |
-
#download from bale
|
24 |
-
|
25 |
-
from balethon import Client
|
26 |
-
from balethon.conditions import document
|
27 |
-
|
28 |
-
bot = Client("1261816176:T4jSrvlJiCfdV5UzUkpywN2HFrzef1IZJs5URAkz")
|
29 |
-
|
30 |
-
|
31 |
-
@bot.on_message(document)
|
32 |
-
async def download_document(client, message):
|
33 |
-
downloading = await message.reply("Downloading...")
|
34 |
-
|
35 |
-
response = await client.download(message.document.id)
|
36 |
-
|
37 |
-
mime_type = message.document.mime_type.split("/")[-1]
|
38 |
-
file_format = mime_type.split(";")[0]
|
39 |
-
with open(f"downloaded file.{file_format}", "wb") as file:
|
40 |
-
file.write(response)
|
41 |
-
|
42 |
-
await downloading.edit_text("Download completed")
|
43 |
-
|
44 |
-
|
45 |
-
bot.run()
|
46 |
-
def fetch_data(url):
|
47 |
-
try:
|
48 |
-
response = requests.get(url)
|
49 |
-
response.raise_for_status()
|
50 |
-
return response.json()
|
51 |
-
except requests.exceptions.RequestException as e:
|
52 |
-
print(f"An error occurred: {e}")
|
53 |
-
return None
|
54 |
-
|
55 |
-
def download_file(url):
|
56 |
-
try:
|
57 |
-
response = requests.get(url.split("#")[0], stream=True)
|
58 |
-
response.raise_for_status()
|
59 |
-
print(url.split("#")[1])
|
60 |
-
with open(url.split("#")[1], 'wb') as file:
|
61 |
-
for chunk in response.iter_content(chunk_size=8192):
|
62 |
-
if chunk:
|
63 |
-
file.write(chunk)
|
64 |
-
print(f"Downloaded successfully: {url.split('#')[1]}")
|
65 |
-
except requests.exceptions.RequestException as e:
|
66 |
-
print(f"An error occurred: {e}")
|
67 |
-
|
68 |
-
def download_chunk(url, start, end, filename, index):
|
69 |
-
headers = {'Range': f'bytes={start}-{end}'}
|
70 |
-
response = requests.get(url, headers=headers, stream=True)
|
71 |
-
response.raise_for_status()
|
72 |
-
chunk_filename = f'{filename}.part{index}'
|
73 |
-
with open(chunk_filename, 'wb') as file:
|
74 |
-
for chunk in response.iter_content(chunk_size=8192):
|
75 |
-
if chunk:
|
76 |
-
file.write(chunk)
|
77 |
-
return chunk_filename
|
78 |
-
|
79 |
-
def merge_files(filename, num_parts):
|
80 |
-
with open(filename, 'wb') as output_file:
|
81 |
-
for i in range(num_parts):
|
82 |
-
part_filename = f'{filename}.part{i}'
|
83 |
-
with open(part_filename, 'rb') as part_file:
|
84 |
-
output_file.write(part_file.read())
|
85 |
-
# Optionally, delete the part file after merging
|
86 |
-
# os.remove(part_filename)
|
87 |
-
|
88 |
-
def download_file_in_parallel(link, size, num_threads=4):
|
89 |
-
url = link.split("#")[0]
|
90 |
-
filename = link.split("#")[1]
|
91 |
-
print(url+" filename: "+filename)
|
92 |
-
response = requests.head(url)
|
93 |
-
#file_size = int(response.headers['Content-Length'])
|
94 |
-
chunk_size = size // num_threads
|
95 |
-
|
96 |
-
ranges = [(i * chunk_size, (i + 1) * chunk_size - 1) for i in range(num_threads)]
|
97 |
-
ranges[-1] = (ranges[-1][0], size - 1) # Adjust the last range to the end of the file
|
98 |
-
|
99 |
-
with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
|
100 |
-
futures = [
|
101 |
-
executor.submit(download_chunk, url, start, end, filename, i)
|
102 |
-
for i, (start, end) in enumerate(ranges)
|
103 |
-
]
|
104 |
-
for future in concurrent.futures.as_completed(futures):
|
105 |
-
future.result() # Ensure all threads complete
|
106 |
-
|
107 |
-
merge_files(filename, num_threads)
|
108 |
-
print(f'Downloaded successfully: {filename}')
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
def one_youtube(link, api_key):
|
113 |
-
|
114 |
-
# Fetch video ID
|
115 |
-
video_id_url = f"https://one-api.ir/youtube/?token={api_key}&action=getvideoid&link={link}"
|
116 |
-
video_data = fetch_data(video_id_url)
|
117 |
-
if not video_data:
|
118 |
-
return None, None
|
119 |
-
|
120 |
-
video_id = video_data["result"]
|
121 |
-
|
122 |
-
# Fetch video data
|
123 |
-
filter_option = "" # Replace with your filter option
|
124 |
-
video_data_url = f"https://youtube.one-api.ir/?token={api_key}&action=fullvideo&id={video_id}&filter={filter_option}"
|
125 |
-
video_data_2 = fetch_data(video_data_url)
|
126 |
-
if not video_data_2:
|
127 |
-
return None, None
|
128 |
-
|
129 |
-
formats_list = video_data_2["result"]["formats"]
|
130 |
-
file_name = video_data_2["result"]["title"]
|
131 |
-
video_name = f'{file_name}.mp4'
|
132 |
-
audio_name = f'{file_name}.mp3'
|
133 |
-
|
134 |
-
for f in formats_list:
|
135 |
-
if f["format_note"] == "360p":
|
136 |
-
download_id = f["id"]
|
137 |
-
video_size = f["filesize"]
|
138 |
-
for f in formats_list:
|
139 |
-
if f["format_note"] == "medium":
|
140 |
-
audio_id = f["id"]
|
141 |
-
audio_size = f["filesize"]
|
142 |
-
|
143 |
-
if not download_id or not audio_id:
|
144 |
-
return None, None
|
145 |
-
|
146 |
-
# Fetch video and audio links
|
147 |
-
video_link_url = f"https://youtube.one-api.ir/?token={api_key}&action=download&id={download_id}"
|
148 |
-
audio_link_url = f"https://youtube.one-api.ir/?token={api_key}&action=download&id={audio_id}"
|
149 |
-
video_link_data = fetch_data(video_link_url)
|
150 |
-
audio_link_data = fetch_data(audio_link_url)
|
151 |
-
if not video_link_data or not audio_link_data:
|
152 |
-
return None, None
|
153 |
-
|
154 |
-
video_link = video_link_data["result"]["link"]
|
155 |
-
audio_link = audio_link_data["result"]["link"]
|
156 |
-
vid_str=video_link+"#"+video_name
|
157 |
-
audio_str=audio_link+"#"+audio_name
|
158 |
-
# Download video and audio files
|
159 |
-
print(video_size , audio_size)
|
160 |
-
download_file_in_parallel(vid_str, video_size)
|
161 |
-
download_file_in_parallel(audio_str, audio_size)
|
162 |
-
|
163 |
-
return video_name, audio_name
|
164 |
-
|
165 |
-
|
166 |
-
# Define your functions here
|
167 |
-
def yt_download(url):
|
168 |
-
yt = YouTube(url)
|
169 |
-
print(yt.title)
|
170 |
-
video_path = f"{yt.title}.mp4"
|
171 |
-
ys = yt.streams.get_highest_resolution()
|
172 |
-
print(ys)
|
173 |
-
ys.download()
|
174 |
-
return video_path, yt.title
|
175 |
-
|
176 |
-
def download_image(url, save_path='downloaded_image.jpg'):
|
177 |
-
response = requests.get(url)
|
178 |
-
image = Image.open(BytesIO(response.content))
|
179 |
-
image.save(save_path)
|
180 |
-
return save_path
|
181 |
-
|
182 |
-
def insta_oneapi(url, api_key):
|
183 |
-
shortcode = url.split("/")[-2]
|
184 |
-
print(shortcode)
|
185 |
-
url_one="https://api.one-api.ir/instagram/v1/post/?shortcode="+shortcode
|
186 |
-
request_body = [{"shortcode": shortcode},]
|
187 |
-
headers = {"one-api-token": api_key, "Content-Type": "application/json"}
|
188 |
-
response = requests.get(url_one, headers=headers)
|
189 |
-
print(response)
|
190 |
-
if response.status_code == 200:
|
191 |
-
|
192 |
-
result = response.json()
|
193 |
-
try:
|
194 |
-
time.sleep(10)
|
195 |
-
response = requests.get(result["result"]['media'][0]["url"], stream=True)
|
196 |
-
response.raise_for_status()
|
197 |
-
with open("video.mp4", 'wb') as file:
|
198 |
-
for chunk in response.iter_content(chunk_size=8192):
|
199 |
-
if chunk:
|
200 |
-
file.write(chunk)
|
201 |
-
print(f"Downloaded successfully")
|
202 |
-
image_url = result["result"]['media'][0]["cover"]
|
203 |
-
image_file_path = download_image(image_url)
|
204 |
-
return "video.mp4", image_file_path
|
205 |
-
except requests.exceptions.RequestException as e:
|
206 |
-
print(f"An error occurred: {e}")
|
207 |
-
else:
|
208 |
-
print(f"Error: {response.status_code}, {response.text}")
|
209 |
-
return None
|
210 |
-
|
211 |
-
|
212 |
-
def insta_download(permalink):
|
213 |
-
# Create an instance of Instaloader
|
214 |
-
L = instaloader.Instaloader()
|
215 |
-
|
216 |
-
try:
|
217 |
-
# Extract the shortcode from the permalink
|
218 |
-
if "instagram.com/reel/" in permalink:
|
219 |
-
shortcode = permalink.split("instagram.com/reel/")[-1].split("/")[0]
|
220 |
-
elif "instagram.com/p/" in permalink:
|
221 |
-
shortcode = permalink.split("instagram.com/p/")[-1].split("/")[0]
|
222 |
-
else:
|
223 |
-
raise ValueError("Invalid permalink format")
|
224 |
-
|
225 |
-
# Load the post using the shortcode
|
226 |
-
post = instaloader.Post.from_shortcode(L.context, shortcode)
|
227 |
-
|
228 |
-
# Check if the post is a video
|
229 |
-
if not post.is_video:
|
230 |
-
raise ValueError("The provided permalink is not a video.")
|
231 |
-
|
232 |
-
# Get the video URL
|
233 |
-
video_url = post.video_url
|
234 |
-
|
235 |
-
# Extract the filename from the URL
|
236 |
-
filename = video_url.split("/")[-1]
|
237 |
-
# Remove query parameters
|
238 |
-
filename = filename.split("?")[0]
|
239 |
-
|
240 |
-
# Download the video using requests
|
241 |
-
response = requests.get(video_url, stream=True)
|
242 |
-
response.raise_for_status() # Raise an error for bad responses
|
243 |
-
|
244 |
-
# Save the content to a file
|
245 |
-
with open(filename, 'wb') as file:
|
246 |
-
for chunk in response.iter_content(chunk_size=8192):
|
247 |
-
file.write(chunk)
|
248 |
-
|
249 |
-
print(f"Downloaded video {filename} successfully.")
|
250 |
-
return filename
|
251 |
-
except Exception as e:
|
252 |
-
print(f"Failed to download video from {permalink}: {e}")
|
253 |
-
|
254 |
def extract_audio(input_video_name):
|
255 |
# Define the input video file and output audio file
|
256 |
mp3_file = "audio.mp3"
|
@@ -271,13 +40,59 @@ def extract_audio(input_video_name):
|
|
271 |
print("Audio extraction successful!")
|
272 |
return mp3_file
|
273 |
|
274 |
-
def transcribe(audio):
|
275 |
-
model = WhisperModel("tiny")
|
276 |
-
segments, info = model.transcribe(audio)
|
277 |
-
segments = list(segments)
|
|
|
278 |
for segment in segments:
|
279 |
-
|
280 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
|
282 |
def format_time(seconds):
|
283 |
hours = math.floor(seconds / 3600)
|
@@ -293,27 +108,17 @@ def generate_subtitle_file(language, segments, input_video_name):
|
|
293 |
subtitle_file = f"sub-{input_video_name}.{language}.srt"
|
294 |
text = ""
|
295 |
for index, segment in enumerate(segments):
|
296 |
-
segment_start = format_time(segment
|
297 |
-
segment_end = format_time(segment
|
298 |
text += f"{str(index+1)} \n"
|
299 |
text += f"{segment_start} --> {segment_end} \n"
|
300 |
-
text += f"{segment
|
301 |
text += "\n"
|
302 |
f = open(subtitle_file, "w", encoding='utf8')
|
303 |
f.write(text)
|
304 |
f.close()
|
305 |
return subtitle_file
|
306 |
|
307 |
-
def read_srt_file(file_path):
|
308 |
-
try:
|
309 |
-
with open(file_path, 'r', encoding='utf-8') as file:
|
310 |
-
srt_content = file.read()
|
311 |
-
return srt_content
|
312 |
-
except FileNotFoundError:
|
313 |
-
print(f"The file {file_path} was not found.")
|
314 |
-
except Exception as e:
|
315 |
-
print(f"An error occurred: {e}")
|
316 |
-
|
317 |
def clean_text(text):
|
318 |
# Remove 'srt ' from the start of each line
|
319 |
# Remove ''' from the start and end
|
@@ -321,13 +126,25 @@ def clean_text(text):
|
|
321 |
text = re.sub(r'^srt', '', text, flags=re.MULTILINE)
|
322 |
return text
|
323 |
|
324 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
url = "https://api.one-api.ir/chatbot/v1/gpt4o/"
|
326 |
|
327 |
# Prepare the request body
|
328 |
request_body = [{
|
329 |
"role": "user",
|
330 |
-
"content":
|
331 |
},]
|
332 |
|
333 |
# Add the API key to the request
|
@@ -337,114 +154,141 @@ def enhance_text(api_key, text, google):
|
|
337 |
}
|
338 |
|
339 |
# Make the POST request
|
340 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
print(
|
349 |
-
|
350 |
-
|
351 |
-
print(f"Error: {response.status_code}, {response.text}")
|
352 |
-
return None
|
353 |
|
354 |
-
def
|
355 |
-
|
356 |
-
|
357 |
-
headers = {"one-api-token": api_key, "Content-Type": "application/json"}
|
358 |
-
response = requests.post(url, headers=headers, json=request_body)
|
359 |
-
if response.status_code == 200:
|
360 |
-
result = response.json()
|
361 |
-
enhanced_text = enhance_text(api_key, text, result['result'])
|
362 |
-
return enhanced_text
|
363 |
-
else:
|
364 |
-
print(f"Error: {response.status_code}, {response.text}")
|
365 |
-
return None
|
366 |
|
367 |
def write_google(google_translate):
|
368 |
google = "google_translate.srt"
|
369 |
with open(google, 'w', encoding="utf-8") as f:
|
370 |
f.write(google_translate)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
|
372 |
def time_to_seconds(time_obj):
|
373 |
return time_obj.hours * 3600 + time_obj.minutes * 60 + time_obj.seconds + time_obj.milliseconds / 1000
|
374 |
|
375 |
def create_subtitle_clips(subtitles, videosize, fontsize, font, color, debug):
|
376 |
subtitle_clips = []
|
|
|
377 |
for subtitle in subtitles:
|
378 |
start_time = time_to_seconds(subtitle.start) # Add 2 seconds offset
|
379 |
end_time = time_to_seconds(subtitle.end)
|
380 |
duration = end_time - start_time
|
381 |
video_width, video_height = videosize
|
382 |
-
max_width = video_width * 0.8
|
383 |
max_height = video_height * 0.2
|
384 |
#reshaped_text = arabic_reshaper.reshape(subtitle.text)
|
385 |
#bidi_text = get_display(reshaped_text)
|
386 |
-
text_clip = TextClip(font, subtitle.text, font_size=fontsize, size=(int(video_width * 0.8), int(video_height * 0.2)) ,text_align="
|
|
|
387 |
subtitle_x_position = 'center'
|
388 |
subtitle_y_position = video_height * 0.68
|
389 |
text_position = (subtitle_x_position, subtitle_y_position)
|
390 |
subtitle_clips.append(text_clip.with_position(text_position))
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
if type=="insta":
|
398 |
-
input_video, image_path=insta_oneapi(url, api_key)
|
399 |
-
input_video_name = input_video.replace(".mp4", "")
|
400 |
-
video = VideoFileClip(input_video)
|
401 |
-
image_clip = ImageClip(image_path).with_duration(1)
|
402 |
-
# Set the position and size of the image (optional)
|
403 |
-
image_clip = image_clip.with_position(("center", "center")).resized(height=video.size[1])
|
404 |
-
first_video = CompositeVideoClip([video.with_start(1), image_clip])
|
405 |
-
input_video = input_video_name+"_cover.mp4"
|
406 |
-
input_video_name = input_video.replace(".mp4", "")
|
407 |
-
first_video.write_videofile(input_video, codec="libx264", audio_codec="aac", logger=None)
|
408 |
-
input_audio = extract_audio(input_video)
|
409 |
-
elif type=="youtube":
|
410 |
-
input_video, input_audio = one_youtube(url, api_key)
|
411 |
-
input_video_name = input_video.replace(".mp4", "")
|
412 |
-
# Get the current local time
|
413 |
-
t = time.localtime()
|
414 |
-
# Format the time as a string
|
415 |
-
current_time = time.strftime("%H:%M:%S", t)
|
416 |
-
print("Current Time =", current_time)
|
417 |
-
segments = transcribe(audio=input_audio)
|
418 |
-
language = "fa"
|
419 |
-
subtitle_file = generate_subtitle_file(language=language, segments=segments, input_video_name=input_video_name)
|
420 |
-
source_language = "en"
|
421 |
-
target_language = "fa"
|
422 |
-
srt_string = read_srt_file(subtitle_file)
|
423 |
-
google_translate = translate_text(api_key, source_language, target_language, srt_string)
|
424 |
-
write_google(google_translate)
|
425 |
video = VideoFileClip(input_video)
|
426 |
audio = AudioFileClip(input_audio)
|
427 |
video = video.with_audio(audio)
|
428 |
print(video)
|
429 |
-
subtitles = pysrt.open("google_translate.srt", encoding="utf-8")
|
430 |
output_video_file = input_video_name + '_subtitled' + ".mp4"
|
431 |
-
|
432 |
-
|
|
|
|
|
433 |
final_video.write_videofile(output_video_file, codec="libx264", audio_codec="aac", logger=None)
|
|
|
434 |
print('final')
|
435 |
-
# Get the current local time
|
436 |
-
t = time.localtime()
|
437 |
-
|
438 |
-
# Format the time as a string
|
439 |
-
current_time = time.strftime("%H:%M:%S", t)
|
440 |
-
print("Current Time =", current_time)
|
441 |
-
|
442 |
-
# Generate the URL for the file
|
443 |
return output_video_file
|
444 |
|
445 |
-
def
|
446 |
-
return gr.File.update(file_path)
|
447 |
|
448 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
449 |
|
450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
api_key = "268976:66f4f58a2a905"
|
21 |
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
def extract_audio(input_video_name):
|
24 |
# Define the input video file and output audio file
|
25 |
mp3_file = "audio.mp3"
|
|
|
40 |
print("Audio extraction successful!")
|
41 |
return mp3_file
|
42 |
|
43 |
+
def transcribe(audio, max_segment_duration=2.0): # Set your desired max duration here
|
44 |
+
model = WhisperModel("tiny", device="cpu")
|
45 |
+
segments, info = model.transcribe(audio, vad_filter=True, vad_parameters=dict(min_silence_duration_ms=1500), word_timestamps=True)
|
46 |
+
segments = list(segments) # The transcription will actually run here.
|
47 |
+
wordlevel_info = []
|
48 |
for segment in segments:
|
49 |
+
for word in segment.words:
|
50 |
+
print("[%.2fs -> %.2fs] %s" % (word.start, word.end, word.word))
|
51 |
+
wordlevel_info.append({'word':word.word,'start':word.start,'end':word.end})
|
52 |
+
return wordlevel_info
|
53 |
+
|
54 |
+
def create_subtitles(wordlevel_info):
|
55 |
+
punctuation_marks = {'.', '!', '?', ',', ';', ':', '—', '-', '。', '!', '?'} # Add/remove punctuation as needed
|
56 |
+
subtitles = []
|
57 |
+
line = []
|
58 |
+
|
59 |
+
for word_data in wordlevel_info:
|
60 |
+
line.append(word_data)
|
61 |
+
current_word = word_data['word']
|
62 |
+
|
63 |
+
# Check if current word ends with punctuation or line reached 5 words
|
64 |
+
ends_with_punct = current_word and (current_word[-1] in punctuation_marks)
|
65 |
+
|
66 |
+
if ends_with_punct or len(line) == 5:
|
67 |
+
# Create a new subtitle segment
|
68 |
+
subtitle = {
|
69 |
+
"word": " ".join(item["word"] for item in line),
|
70 |
+
"start": line[0]["start"],
|
71 |
+
"end": line[-1]["end"],
|
72 |
+
"textcontents": line.copy()
|
73 |
+
}
|
74 |
+
subtitles.append(subtitle)
|
75 |
+
line = []
|
76 |
+
|
77 |
+
# Add remaining words if any
|
78 |
+
if line:
|
79 |
+
subtitle = {
|
80 |
+
"word": " ".join(item["word"] for item in line),
|
81 |
+
"start": line[0]["start"],
|
82 |
+
"end": line[-1]["end"],
|
83 |
+
"textcontents": line.copy()
|
84 |
+
}
|
85 |
+
subtitles.append(subtitle)
|
86 |
+
|
87 |
+
# Remove gaps between segments by extending the previous segment's end time
|
88 |
+
for i in range(1, len(subtitles)):
|
89 |
+
prev_subtitle = subtitles[i - 1]
|
90 |
+
current_subtitle = subtitles[i]
|
91 |
+
|
92 |
+
# Extend the previous segment's end time to the start of the current segment
|
93 |
+
prev_subtitle["end"] = current_subtitle["start"]
|
94 |
+
|
95 |
+
return subtitles
|
96 |
|
97 |
def format_time(seconds):
|
98 |
hours = math.floor(seconds / 3600)
|
|
|
108 |
subtitle_file = f"sub-{input_video_name}.{language}.srt"
|
109 |
text = ""
|
110 |
for index, segment in enumerate(segments):
|
111 |
+
segment_start = format_time(segment['start'])
|
112 |
+
segment_end = format_time(segment['end'])
|
113 |
text += f"{str(index+1)} \n"
|
114 |
text += f"{segment_start} --> {segment_end} \n"
|
115 |
+
text += f"{segment['word']} \n"
|
116 |
text += "\n"
|
117 |
f = open(subtitle_file, "w", encoding='utf8')
|
118 |
f.write(text)
|
119 |
f.close()
|
120 |
return subtitle_file
|
121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
def clean_text(text):
|
123 |
# Remove 'srt ' from the start of each line
|
124 |
# Remove ''' from the start and end
|
|
|
126 |
text = re.sub(r'^srt', '', text, flags=re.MULTILINE)
|
127 |
return text
|
128 |
|
129 |
+
def translate_text(api_key, text, source_language = "en", target_language = "fa"):
|
130 |
+
url = "https://api.one-api.ir/translate/v1/google/"
|
131 |
+
request_body = {"source": source_lang, "target": target_lang, "text": text}
|
132 |
+
headers = {"one-api-token": api_key, "Content-Type": "application/json"}
|
133 |
+
response = requests.post(url, headers=headers, json=request_body)
|
134 |
+
if response.status_code == 200:
|
135 |
+
result = response.json()
|
136 |
+
return result['result']
|
137 |
+
else:
|
138 |
+
print(f"Error: {response.status_code}, {response.text}")
|
139 |
+
return None
|
140 |
+
|
141 |
+
def enhance_text(api_key, text):
|
142 |
url = "https://api.one-api.ir/chatbot/v1/gpt4o/"
|
143 |
|
144 |
# Prepare the request body
|
145 |
request_body = [{
|
146 |
"role": "user",
|
147 |
+
"content": f"i will provide you with an english subtitle of a clip which is in srt format and i need you to translate each line in persian an return in a srt format without changing the original timing, converting the English terms used, into common Persian terms. in respose dont add any thing and keep the srt format, keep in mind the duraetion of the end of the srt should be the same as the duaration of the clip. subtitle: {text} "
|
148 |
},]
|
149 |
|
150 |
# Add the API key to the request
|
|
|
154 |
}
|
155 |
|
156 |
# Make the POST request
|
157 |
+
attempts = 0
|
158 |
+
max_attempts = 3
|
159 |
+
|
160 |
+
while attempts < max_attempts:
|
161 |
+
response = requests.post(url, headers=headers, json=request_body)
|
162 |
+
if response.status_code == 200:
|
163 |
+
result = response.json()
|
164 |
+
if result["status"] == 200:
|
165 |
+
print("status: ", result["status"])
|
166 |
+
te = clean_text(result["result"][0])
|
167 |
+
print("result: ", te)
|
168 |
+
return te
|
169 |
+
else:
|
170 |
+
print(f"Error: status {result['status']}, retrying in 30 seconds...")
|
171 |
+
else:
|
172 |
+
print(f"Error: {response.status_code}, {response.text}, retrying in 30 seconds...")
|
173 |
+
attempts += 1
|
174 |
+
time.sleep(30)
|
175 |
+
print("Error Max attempts reached. Could not retrieve a successful response.")
|
176 |
+
te = translate_text(api_key, text)
|
177 |
+
return te
|
178 |
|
179 |
+
def read_srt_file(file_path):
|
180 |
+
try:
|
181 |
+
with open(file_path, 'r', encoding='utf-8') as file:
|
182 |
+
srt_content = file.read()
|
183 |
+
return srt_content
|
184 |
+
except FileNotFoundError:
|
185 |
+
print(f"The file {file_path} was not found.")
|
186 |
+
except Exception as e:
|
187 |
+
print(f"An error occurred: {e}")
|
|
|
|
|
188 |
|
189 |
+
def write_srt(subtitle_text, output_file="edited_srt.srt"):
|
190 |
+
with open(output_file, 'w', encoding="utf-8") as file:
|
191 |
+
file.write(subtitle_text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
|
193 |
def write_google(google_translate):
|
194 |
google = "google_translate.srt"
|
195 |
with open(google, 'w', encoding="utf-8") as f:
|
196 |
f.write(google_translate)
|
197 |
+
return google
|
198 |
+
|
199 |
+
def generate_translated_subtitle(language, segments, input_video_name):
|
200 |
+
input_video_name=input_video_name.split('/')[-1]
|
201 |
+
subtitle_file = f"{input_video_name}.srt"
|
202 |
+
text = ""
|
203 |
+
lines = segments.split('\n')
|
204 |
+
new_list = [item for item in lines if item != '']
|
205 |
+
segment_number = 1
|
206 |
+
|
207 |
+
for index, segment in enumerate(new_list):
|
208 |
+
if (index+1) % 3 == 1 or (index+1)==1:
|
209 |
+
text += f"{segment}\n"
|
210 |
+
segment_number += 1
|
211 |
+
if (index+1) % 3 == 2 or (index+1)==2:
|
212 |
+
text += segment + "\n"
|
213 |
+
if (index+1) % 3 == 0:
|
214 |
+
text += f"\u200F{segment}\n\n"
|
215 |
+
|
216 |
+
with open(subtitle_file, "w", encoding='utf8') as f:
|
217 |
+
f.write(text)
|
218 |
+
return subtitle_file
|
219 |
|
220 |
def time_to_seconds(time_obj):
|
221 |
return time_obj.hours * 3600 + time_obj.minutes * 60 + time_obj.seconds + time_obj.milliseconds / 1000
|
222 |
|
223 |
def create_subtitle_clips(subtitles, videosize, fontsize, font, color, debug):
|
224 |
subtitle_clips = []
|
225 |
+
color_clips=[]
|
226 |
for subtitle in subtitles:
|
227 |
start_time = time_to_seconds(subtitle.start) # Add 2 seconds offset
|
228 |
end_time = time_to_seconds(subtitle.end)
|
229 |
duration = end_time - start_time
|
230 |
video_width, video_height = videosize
|
231 |
+
max_width = video_width * 0.8
|
232 |
max_height = video_height * 0.2
|
233 |
#reshaped_text = arabic_reshaper.reshape(subtitle.text)
|
234 |
#bidi_text = get_display(reshaped_text)
|
235 |
+
text_clip = TextClip(font, subtitle.text, font_size=fontsize, size=(int(video_width * 0.8), int(video_height * 0.2)) ,text_align="right" ,color=color, method='caption').with_start(start_time).with_duration(duration)
|
236 |
+
myclip = ColorClip(size=(int(video_width * 0.8), int(video_height * 0.2)) , color=(225, 0, 0)).with_opacity(0.2).with_start(start_time).with_duration(duration)
|
237 |
subtitle_x_position = 'center'
|
238 |
subtitle_y_position = video_height * 0.68
|
239 |
text_position = (subtitle_x_position, subtitle_y_position)
|
240 |
subtitle_clips.append(text_clip.with_position(text_position))
|
241 |
+
color_clips.append(myclip.with_position(text_position))
|
242 |
+
return subtitle_clips, color_clips
|
243 |
+
|
244 |
+
def video_edit(srt, input_video, input_audio= "audio.mp3"):
|
245 |
+
input_video_name = "video"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 |
video = VideoFileClip(input_video)
|
247 |
audio = AudioFileClip(input_audio)
|
248 |
video = video.with_audio(audio)
|
249 |
print(video)
|
|
|
250 |
output_video_file = input_video_name + '_subtitled' + ".mp4"
|
251 |
+
#write_srt(srt)
|
252 |
+
subtitles = pysrt.open("video_subtitled.srt", encoding="utf-8")
|
253 |
+
subtitle_clips, color_clips = create_subtitle_clips(subtitles, video.size, 24, 'arial-unicode-ms.ttf', 'white', False)
|
254 |
+
final_video = CompositeVideoClip([video]+color_clips + subtitle_clips)
|
255 |
final_video.write_videofile(output_video_file, codec="libx264", audio_codec="aac", logger=None)
|
256 |
+
#os.remove("google_translate.srt")
|
257 |
print('final')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
return output_video_file
|
259 |
|
260 |
+
def process_video(video, clip_type):
|
|
|
261 |
|
262 |
+
mp3_file=extract_audio(video)
|
263 |
+
wordlevel_info=transcribe(mp3_file)
|
264 |
+
subtitles = create_subtitles(wordlevel_info)
|
265 |
+
subtitle_file = generate_subtitle_file('fa', subtitles, 'video_subtitled')
|
266 |
+
srt_string = read_srt_file(subtitle_file)
|
267 |
+
google_translate = enhance_text(api_key, srt_string)
|
268 |
+
srt = write_google(google_translate)
|
269 |
+
#segments = pysrt.open(srt, encoding="utf-8")
|
270 |
+
sub = generate_translated_subtitle("fa", google_translate, "video_subtitled")
|
271 |
+
output_video_file = video_edit(sub, video, input_audio= "audio.mp3")
|
272 |
+
|
273 |
+
return output_video_file
|
274 |
|
275 |
+
with gr.Blocks() as demo:
|
276 |
+
gr.Markdown("Start typing below and then click **Run** to see the output.")
|
277 |
+
with gr.Column():
|
278 |
+
video_file_input = gr.Video(label="Upload Video File")
|
279 |
+
clip_type = gr.Dropdown(["auto edit", "default"], label="Clip Type")
|
280 |
+
btn = gr.Button("create")
|
281 |
+
video_file_output = gr.Video(label="result: ")
|
282 |
+
btn.click(fn=process_video, inputs=[video_file_input, clip_type], outputs=video_file_output)
|
283 |
+
""" with gr.Row():
|
284 |
+
vid_out = gr.Video()
|
285 |
+
srt_file = gr.File()
|
286 |
+
btn2 = gr.Button("transcribe")
|
287 |
+
gr.on(
|
288 |
+
triggers=[btn2.click],
|
289 |
+
fn=write_google,
|
290 |
+
inputs=out,
|
291 |
+
).then(video_edit, [out, video_path_output, audio_path_output], outputs=[vid_out, srt_file])"""
|
292 |
+
|
293 |
+
|
294 |
+
demo.launch(debug=True)
|