Skip to content

Commit 11942bb

Browse files
committed
Add option to process folder with videos
1 parent 5402c58 commit 11942bb

File tree

3 files changed

+56
-15
lines changed

3 files changed

+56
-15
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ The following command will generate a `subtitled/video.mp4` file contained the i
3939

4040
faster_auto_subtitle /path/to/video.mp4 -o subtitled/
4141

42+
You can also specify a folder with multiple videos, and it will process all of them:
43+
44+
faster_auto_subtitle /path/to/videos/ -o subtitled/
45+
4246
The default setting (which selects the `small` model) works well for transcribing English. You can optionally use a
4347
bigger model for better results (especially with other languages). The available models
4448
are `tiny`, `tiny.en`, `base`, `base.en`, `small`, `small.en`, `medium`, `medium.en`, `large`, `large-v1`, `large-v2`, `large-v3`.

auto_subtitle/main.py

+40-13
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import Optional
55
from .models.Subtitles import Subtitles, SegmentsIterable
66
from .utils.files import filename, write_srt
7-
from .utils.ffmpeg import get_audio, add_subtitles, preprocess_audio
7+
from .utils.ffmpeg import get_audio, add_subtitles, preprocess_audio, file_has_audio
88
from .utils.whisper import WhisperAI
99
from .translation.easynmt_utils import EasyNMTWrapper
1010

@@ -39,7 +39,7 @@ def process(args: dict):
3939
"subtitle_type": args.pop("subtitle_type")
4040
}
4141

42-
videos = args.pop('video')
42+
paths_to_process = args.pop('video')
4343
audio_channel = args.pop('audio_channel')
4444
model_args = {
4545
"model_size_or_path": model_name,
@@ -51,16 +51,42 @@ def process(args: dict):
5151
device=model_args['device']) if target_language != 'en' else None
5252

5353
os.makedirs(output_args["output_dir"], exist_ok=True)
54-
for video in videos:
55-
if video.endswith('.wav'):
56-
audio = preprocess_audio(video, audio_channel, sample_interval)
57-
else:
58-
audio = get_audio(video, audio_channel, sample_interval)
54+
for path_to_process in paths_to_process:
55+
process_path(audio_channel, language, output_args, path_to_process, sample_interval,
56+
target_language, transcribe_model, translate_model)
5957

60-
transcribed, translated = perform_task(video, audio, language, target_language,
61-
transcribe_model, translate_model)
6258

63-
save_result(video, transcribed, translated, sample_interval, output_args)
59+
def process_path(audio_channel, language, output_args, path_to_process, sample_interval,
60+
target_language, transcribe_model, translate_model):
61+
if not os.path.exists(path_to_process):
62+
logger.error("File %s does not exist.", path_to_process)
63+
return
64+
65+
if not os.path.isdir(path_to_process):
66+
process_file(audio_channel, language, output_args, sample_interval, target_language,
67+
transcribe_model, translate_model, path_to_process)
68+
return
69+
70+
logger.info("Processing all files in directory %s", path_to_process)
71+
for file_name in os.listdir(path_to_process):
72+
process_file(audio_channel, language, output_args, sample_interval, target_language,
73+
transcribe_model, translate_model, os.path.join(path_to_process, file_name))
74+
75+
76+
def process_file(audio_channel, language, output_args, sample_interval, target_language,
77+
transcribe_model, translate_model, file_name):
78+
if not file_has_audio(file_name):
79+
logger.info("File %s has no audio, skipping.", file_name)
80+
return
81+
82+
if file_name.endswith('.wav'):
83+
audio = preprocess_audio(file_name, audio_channel, sample_interval)
84+
else:
85+
audio = get_audio(file_name, audio_channel, sample_interval)
86+
87+
transcribed, translated = perform_task(file_name, audio, language, target_language,
88+
transcribe_model, translate_model)
89+
save_result(file_name, transcribed, translated, sample_interval, output_args)
6490

6591

6692
def save_result(video: str, transcribed: Subtitles, translated: Subtitles, sample_interval: list,
@@ -84,9 +110,7 @@ def perform_task(video: str, audio: str, language: str, target_language: str,
84110
transcribed = get_subtitles(video, audio, transcribe_model)
85111
translated = None
86112

87-
logger.info('Subtitles generated.')
88113
if target_language != 'en':
89-
logger.info('Translating subtitles... This might take a while.')
90114
translated = translate_subtitles(
91115
transcribed, language, target_language, translate_model)
92116

@@ -99,8 +123,11 @@ def translate_subtitles(subtitles: Subtitles, source_lang: str, target_lang: str
99123
if src_lang == '' or src_lang is None:
100124
src_lang = subtitles.language
101125

126+
segments = list(subtitles.segments)
127+
logger.info('Subtitles generated.')
128+
logger.info('Translating subtitles... This might take a while.')
102129
translated_segments = model.translate(
103-
list(subtitles.segments), src_lang, target_lang)
130+
segments, src_lang, target_lang)
104131

105132
return Subtitles(SegmentsIterable(translated_segments), target_lang)
106133

auto_subtitle/utils/ffmpeg.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import os
22
import tempfile
33
import logging
4-
from typing import Optional
54
import ffmpeg
5+
from typing import Optional
66
from .tempfile import SubtitlesTempFile
77
from .files import filename
88
from ..models.Subtitles import Subtitles
@@ -39,6 +39,16 @@ def get_audio(path: str, audio_channel_index: int, sample_interval: Optional[lis
3939
return output_path
4040

4141

42+
def file_has_audio(path: str) -> bool:
43+
try:
44+
audio_info = ffmpeg.probe(path, select_streams='a')
45+
return 'streams' in audio_info \
46+
and audio_info['streams'] is not None \
47+
and len(audio_info['streams']) > 0
48+
except ffmpeg.Error:
49+
return False
50+
51+
4252
def preprocess_audio(path: str, audio_channel_index: int, sample_interval: Optional[list]) -> str:
4353
if sample_interval is not None or audio_channel_index != 0:
4454
return get_audio(path, audio_channel_index, sample_interval)
@@ -71,7 +81,7 @@ def add_subtitles(path: str, transcribed: Subtitles, translated: Optional[Subtit
7181
ffmpeg_output_args['t'] = str(
7282
sample_interval[1] - sample_interval[0])
7383

74-
# HACK: On Windows it's impossible to use absolute subtitle file path with ffmpeg
84+
# HACK: On Windows it's impossible to use absolute subtitle file path with ffmpeg,
7585
# so we use temp copy instead
7686
# see: https://github.com/kkroening/ffmpeg-python/issues/745
7787
with SubtitlesTempFile(transcribed) as transcribed_tmp, SubtitlesTempFile(

0 commit comments

Comments
 (0)