Skip to content

Instantly share code, notes, and snippets.

@albert-tomanek
Last active June 26, 2023 19:35
Show Gist options
  • Save albert-tomanek/8e4331f082c24c7e36d61b97fa415487 to your computer and use it in GitHub Desktop.
Save albert-tomanek/8e4331f082c24c7e36d61b97fa415487 to your computer and use it in GitHub Desktop.
import os
import subprocess, time, signal, glob
import webvtt
sub_lang = 'cs'
id_list = '''nUX6NfpYEmw
qlP_FUCNQwg
cFguVw8h0vc
DjfRVzZ2lWY
n8qeNcPtTtU
RGLqBFJyCPI
0p-YOA_lAek
kgWfM0-GxkU
FSl_g6GGCMg
hX2DecOD05c
hWzhicP-jkE
wLrO7a0jmLg
_PsZg5dl0L0
yynetNC0v5k
Du_ZG5gjE7w
3HKWGUcVwdQ
-MU86m86POg
nexM-WWkSs8
k-yyq0j-KC4
XA7BdFQF7ZY
Z1gD4Vo0M6k
t8hykPA70GE
PXq8PDRC7ck
pgEP9Lb2duo
XT5qwbIzbuE
TvGUFSnbbG0
6ozJinVRbdI
5FQ61aizuZU
1lPY-qT5hcs
PrzUBHNJlHs
kp_ZtYvJi1o
tm7snCgmvLc
IcWXoO1WXhQ
1W1JoJR8SQo
6-jnP8QqOUw
1bVp6xBBuus
9GrAkXjfRuA
_Y34ZPi82Fo
Bg24RlEUwgE
6pKdqfB7mM8
JTJO90_RHOY
Y2sm4Ypgylc
EEOm-j5RFXk
oGVsSZe57Ik
UPl2PuRBtqk
Afn8pK9NVKc
DWRG2QeXmfs
nJ52E0JkbeY
xB_KWPROgJs
rOYxs3_lCXY
Iucv-dqb2Pg
mD31MEvr6JY
wnFrBpXQMQI
4pPzByqG_04
NB4ZpkjOD7I
vRqwk0O7CW4
UunLvOltKz8
9zaEZSgqddE
p6tdM8tQzhA
PRtkP6MqJcg
KnN3rFYU1FY
mboVahIsO2Q
dp3ScJ-aLrY
oiJP-7dkBYc
QxcPXkOOeIY
4B8oStsWv2s
kSV8GX1yP2w
84KAkq3QRFI
G0Pqxahi_sE
GTso45P2jM4
_P6j8IC2u6g
CNgyQOKG_OY
mPDehWjoseU
0SDAdeLkAMw
-UTMAfqxcaI
eT4BFXTCIF4
iAfI7qYKp_o
jAMi3UAG_C0
oTMAX-4nBv4
Bwy7fjkME9A
cn9kIH4jKyQ
grDZDi_w7u0
0KWpXykHbJg
2XtlXBLJc90
KlRCojODWfk
37kAL1ewfz4
DX4O-fG2jxw
GtznnYVpMko
9Vh_7Uky5uM
j-CURxWQB44
e5V0U8ksoZs
ZIo66sOlFYU
X19HI6M3XoU'''.splitlines()
### 1) Download videos
for i, v in enumerate(id_list):
print(f'{i}/{len(id_list)}')
os.system(f'yt-dlp -f18 "youtu.be/{v}"')
### 2) Download vtt files
# yt-dlp --list-subs
for i, v in enumerate(id_list):
print(f'{i}/{len(id_list)}')
os.system(f'yt-dlp --sub-format vtt --sub-langs {sub_lang} "youtu.be/{v}"')
### 3) Extract vtt to txt
for f in glob.glob('*.vtt'):
vtt = webvtt.read(f)
transcript = ""
lines = []
for line in vtt:
# Strip the newlines from the end of the text.
# Split the string if it has a newline in the middle
# Add the lines to an array
lines.extend(line.text.strip().splitlines())
# Remove repeated lines
previous = None
for line in lines:
if line == previous:
continue
transcript += " " + line
previous = line
with open(f+'.txt','w+') as o:
out.write(transcript)
### 4) Use Google TTS to speak text files
for f in glob.glob('*.txt'): # First we gotta remove newlines, else the reading stops mid-sentence
with open(f) as i:
text = i.read()
text.replace('\n', ' ')
os.system(f'rm "{f}"')
with open(f, 'w+') as o:
o.write(text)
for i, f in enumerate(glob.glob('*.txt')):
print(f'{i}/{len(id_list)}')
os.system(f'gtts-cli -l {sub_lang} -f "{f}" -o "{f}.mp3"') # gtts-cli --all
### 5) Stretch the audio files to the same length as the videos and add them into the videos
def adjust_audio_duration(video_path, audio_path):
video_duration = get_video_duration(video_path)
audio_duration = get_audio_duration(audio_path)
if video_duration == audio_duration:
print("Audio duration already matches video duration.")
return
output_audio_path = audio_path.replace(".mp3", "_adjusted.mp3")
os.system(f'ffmpeg -i "{audio_path}" "{audio_path}.wav"')
# Use rubberband to adjust audio duration
rubberband_command = f"rubberband -q -D {video_duration} \"{audio_path}.wav\" \"{output_audio_path}\""
os.system(rubberband_command)
# Use ffmpeg to burn adjusted audio into the video
output_video_path = video_path.replace(".mp4", ".spoken.mp4")
ffmpeg_command = f"ffmpeg -i \"{video_path}\" -i \"{output_audio_path}\" -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 -shortest \"{output_video_path}\""
os.system(ffmpeg_command)
# Clean up intermediate files
os.remove(output_audio_path)
os.remove(audio_path+'.wav')
print(f"Adjusted audio duration and burned it into the video: {output_video_path}")
def get_video_duration(video_path):
ffprobe_command = f"ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \"{video_path}\""
result = os.popen(ffprobe_command).read()
return float(result.strip())
def get_audio_duration(audio_path):
ffprobe_command = f"ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \"{audio_path}\""
result = os.popen(ffprobe_command).read()
return float(result.strip())
# Specify the directory containing the video and audio files
directory = './'
# Iterate over the files in the directory
i = 0
for file_name in os.listdir(directory):
if file_name.endswith('.mp4'):
video_path = os.path.join(directory, file_name)
audio_path = os.path.join(directory, file_name.replace(".mp4", f".{sub_lang}.vtt.txt.mp3"))
if os.path.isfile(audio_path):
adjust_audio_duration(video_path, audio_path)
print(f'========================================================================\n{i}/{len(id_list)}\n=======================================================================')
i+=1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment