Last active
June 26, 2023 19:35
-
-
Save albert-tomanek/8e4331f082c24c7e36d61b97fa415487 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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