File size: 14,326 Bytes
068ed60 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
from msvcrt import getch
from os import listdir, makedirs, path
from shutil import rmtree
from typing import Dict, List
from natsort import natsorted
from constants import (WORKING_SPACE,
WORKING_SPACE_OUTPUT,
WORKING_SPACE_TEMP,
WORKING_SPACE_TEMP_MAIN_SUBS,
WORKING_SPACE_TEMP_ALT_SUBS,
console)
from data.settings import Settings
from modules.mkvtoolnix import MkvToolNix
from modules.subtitle import SubtitleRefactor
from modules.subtitle_to_speech import SubtitleToSpeech
from modules.translator import SubtitleTranslator
from modules.mkv_processing import MKVProcessing
from utils.cool_animation import CoolAnimation
from utils.execution_timer import execution_timer
def check_and_create_directories(directories: List[str]): # ✅
"""
Checks if the given directories exist, and if not, creates them.
Args:
directories (List[str]): A list of directory paths to check and create.
"""
for directory in directories:
if not path.exists(directory):
makedirs(directory)
def display_logo(): # ✅
"""
Displays the logo of the application using the CoolAnimation class.
"""
mm_avh_logo: CoolAnimation = CoolAnimation()
mm_avh_logo.display()
console.print(
'╚═══ Multimedia Magic – Audio Visual Heaven ═══╝\n', style='white_bold')
def ask_user(question: str) -> bool:
"""
Asks the user a yes/no question and returns the response.
Args:
question (str): The question to ask the user.
Returns:
bool: True if the user answers yes, False otherwise.
"""
console.print(question, style='bold green', end=' ')
return input().lower() in ('t', 'y')
def update_settings() -> Settings: # ✅
"""
Asks the user if they want to update the settings. If yes, updates the settings and saves them to a file.
Returns:
Settings: The updated settings.
"""
if ask_user('💾 Czy chcesz zmienić ustawienia? (T lub Y - tak):'):
Settings.change_settings_save_to_file()
console.print('Zapisano ustawienia.\n', style='green_bold')
else:
console.print('Pomijam tę opcję.\n', style='red_bold')
return Settings.load_from_file()
def extract_tracks_from_mkv(): # ✅
"""
Asks the user if they want to extract tracks from MKV files. If yes, extracts the tracks.
"""
if ask_user('🧲 Czy chcesz wyciągnąć ścieżki z plików mkv? (T lub Y - tak):'):
files: List[str] = get_mkv_files(WORKING_SPACE)
sorted_files: List[str] = natsorted(files)
for filename in sorted_files:
mkv: MkvToolNix = MkvToolNix(filename)
mkv.mkv_extract_track(mkv.get_mkv_info())
else:
console.print('Pomijam tę opcję.\n', style='red_bold')
def get_mkv_files(directory: str) -> List[str]:
"""
Gets all MKV files in a directory.
Args:
directory (str): The directory to search for MKV files.
Returns:
List[str]: A list of MKV files in the directory.
"""
return [file for file in listdir(directory)
if path.isfile(path.join(directory, file)) and file.endswith('.mkv')]
def refactor_subtitles(): # ✅
"""
Refactors subtitles in various formats to a standard format.
"""
subtitle_extensions: List[str] = [
'.sup', '.txt', '.ogg',
'.ssa', '.ass', '.srt',
'.sub', '.usf', '.vtt',
]
files: List[str] = get_files_with_extensions(
WORKING_SPACE_TEMP, subtitle_extensions)
sorted_files = natsorted(files)
for filename in sorted_files:
refactor_subtitle_file(filename)
def get_files_with_extensions(directory: str, extensions: List[str]) -> List[str]:
"""
Gets all files in a directory with certain extensions.
Args:
directory (str): The directory to search for files.
extensions (List[str]): The extensions to look for.
Returns:
List[str]: A list of files in the directory with the specified extensions.
"""
return [
file for file in listdir(directory)
if (
path.isfile(path.join(directory, file)) and
any(file.endswith(ext) for ext in extensions)
)
]
def refactor_subtitle_file(filename: str):
"""
Refactors a subtitle file to a standard format.
Args:
filename (str): The name of the subtitle file to refactor.
"""
subtitle: SubtitleRefactor = SubtitleRefactor(filename)
if filename.endswith('.ass') or filename.endswith('.ssa'):
subtitle.split_ass()
subtitle.ass_to_srt()
if filename.endswith('.srt'):
subtitle.move_srt()
if filename.endswith('.txt'):
subtitle.txt_to_srt(10)
def translate_subtitles(settings: Settings): # ✅
"""
Asks the user if they want to translate subtitle files. If yes, translates the files.
Args:
settings (Settings): The settings to use for translation.
"""
if not ask_user('💭 Czy chcesz tłumaczyć pliki napisów? (T lub Y - tak):'):
console.print('Pomijam tę opcję.\n', style='red_bold')
return
main_subs_files = get_srt_files(WORKING_SPACE_TEMP_MAIN_SUBS)
files_to_translate = ask_to_translate_files(main_subs_files)
translate_files(files_to_translate, settings)
def get_srt_files(directory: str) -> List[str]:
"""
Gets all SRT files in a directory.
Args:
directory (str): The directory to search for SRT files.
Returns:
List[str]: A list of SRT files in the directory.
"""
return [
filename for filename in listdir(directory)
if path.isfile(path.join(directory, filename)) and filename.endswith('.srt')
]
def ask_to_translate_files(files: List[str]) -> dict:
"""
Asks the user which files they want to translate.
Args:
files (List[str]): A list of files to ask about.
Returns:
dict: A dictionary mapping file names to a boolean indicating whether the user wants to translate them.
"""
files_to_translate: dict = {}
for filename in files:
console.print("\nTŁUMACZENIE PLIKU:", style='yellow_bold')
console.print(filename, style='white_bold')
if ask_user("Czy chcesz przetłumaczyć (T lub Y - tak):"):
files_to_translate[filename] = True
else:
console.print('Pomijam tę opcję.\n', style='red_bold')
files_to_translate[filename] = False
return files_to_translate
def translate_files(files_to_translate: dict, settings: Settings):
"""
Translates the specified files.
Args:
files_to_translate (dict): A dictionary mapping file names to a boolean indicating whether to translate them.
settings (Settings): The settings to use for translation.
"""
translator_instance: SubtitleTranslator = SubtitleTranslator()
for filename, should_translate in files_to_translate.items():
if should_translate:
translator_instance.translate_srt(filename,
WORKING_SPACE_TEMP_MAIN_SUBS,
settings)
if path.exists(path.join(WORKING_SPACE_TEMP_ALT_SUBS, filename)):
translator_instance.translate_srt(filename,
WORKING_SPACE_TEMP_ALT_SUBS,
settings)
def convert_numbers_to_words(): # ✅
"""
Asks the user if they want to convert numbers to words in the text. If yes, performs the conversion.
"""
if not ask_user('🔢 Czy chcesz przekonwertować liczby na słowa w tekście? (T lub Y - tak):'):
console.print('Pomijam tę opcję.\n', style='red_bold')
return
srt_files = get_srt_files(WORKING_SPACE_TEMP_MAIN_SUBS)
convert_numbers_in_files(srt_files)
def get_srt_files(directory: str) -> List[str]:
"""
Gets all SRT files in a directory.
Args:
directory (str): The directory to search for SRT files.
Returns:
List[str]: A list of SRT files in the directory.
"""
return [
file for file in listdir(directory)
if path.isfile(path.join(directory, file)) and file.endswith('.srt')
]
def convert_numbers_in_files(files: List[str]):
"""
Converts numbers to words in the specified files.
Args:
files (List[str]): A list of files to convert numbers in.
"""
for filename in files:
console.print(
"\nKONWERSJA LICZB (BEZ POPRAWNOŚCI GRAMATYCZNEJ) W PLIKU:", style='yellow_bold')
console.print(filename, style='white_bold')
if ask_user("Czy chcesz przekonwertować liczby na słowa w tym pliku? (T lub Y - tak):"):
subtitle: SubtitleRefactor = SubtitleRefactor(filename)
subtitle.convert_numbers_in_srt()
else:
console.print(f'Pomijam plik {filename}.\n', style='red_bold')
def generate_audio_for_subtitles(settings: Settings) -> None: # ✅
"""
Asks the user if they want to generate audio for subtitles. If yes, generates the audio.
Args:
settings (Settings): The settings to use for audio generation.
"""
if not ask_user('🎤 Czy chcesz generować audio dla napisów? (T lub Y - tak):'):
console.print('Pomijam tę opcję.\n', style='red_bold')
return
main_subs_files: List[str] = get_srt_files(WORKING_SPACE_TEMP_MAIN_SUBS)
files_to_generate_audio: Dict[str, bool] = ask_to_generate_audio_files(
main_subs_files)
generate_audio_files(files_to_generate_audio, settings)
def ask_to_generate_audio_files(files: List[str]) -> Dict[str, bool]:
"""
Asks the user which files they want to generate audio for.
Args:
files (List[str]): A list of files to ask about.
Returns:
dict: A dictionary mapping file names to a boolean indicating whether the user wants to generate audio for them.
"""
files_to_generate_audio: Dict[str, bool] = {}
for filename in files:
console.print("\nGENEROWANIE AUDIO DLA PLIKU:", style='yellow_bold')
console.print(filename, style='white_bold')
if ask_user("Czy chcesz wygenerować audio dla tego pliku? (T lub Y - tak):"):
files_to_generate_audio[filename] = True
else:
console.print('Pomijam tę opcję.', style='red_bold')
files_to_generate_audio[filename] = False
return files_to_generate_audio
def generate_audio_files(files_to_generate_audio: Dict[str, bool], settings: Settings) -> None:
"""
Generates audio for the specified files.
Args:
files_to_generate_audio (Dict[str, bool]): A dictionary mapping file names to a boolean indicating whether the user wants to generate audio for them.
settings (Settings): The settings to use for audio generation.
"""
audio_generator: SubtitleToSpeech
if 'TTS - *Głos* - ElevenLans' in settings.tts:
audio_generator = SubtitleToSpeech('')
audio_generator.srt_to_eac3_elevenlabs()
else:
for filename, should_generate_audio in files_to_generate_audio.items():
if should_generate_audio:
audio_generator = SubtitleToSpeech(filename)
audio_generator.generate_audio(settings)
def refactor_alt_subtitles(): # ✅
"""
Refactors alternative subtitles to a standard format.
"""
files: List[str] = get_srt_files(WORKING_SPACE_TEMP_ALT_SUBS)
sorted_files = natsorted(files)
for filename in sorted_files:
subtitle: SubtitleRefactor = SubtitleRefactor(filename)
subtitle.srt_to_ass()
def process_output_files(settings: Settings):
"""
Processes output files based on user settings.
Args:
settings (Settings): The settings to use for processing.
"""
files = listdir(WORKING_SPACE_OUTPUT)
files_dict = {path.splitext(file)[0]: [] for file in files}
for file in files:
if not file.endswith(('.mkv', '.mp4')):
files_dict[path.splitext(file)[0]].append(file)
for base_name, files in files_dict.items():
if len(files) > 0:
# https://trac.ffmpeg.org/wiki/Encode/H.264
# crf_value => 0 ... 18 ... 23 ... 51 ... :(
# preset_value => 'ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium', 'slow', 'slower', 'veryslow', 'placebo'
subtitle_processor = MKVProcessing(filename=base_name,
crf_value='18',
preset_value='medium')
subtitle_processor.process_mkv(settings)
def clear_temp_folders():
"""
Clears temporary folders used during processing.
"""
folders = [WORKING_SPACE_TEMP, WORKING_SPACE_TEMP_MAIN_SUBS,
WORKING_SPACE_TEMP_ALT_SUBS]
for folder in folders:
rmtree(folder, ignore_errors=True)
makedirs(folder, exist_ok=True)
@execution_timer # ✅
def main():
"""
Main function that runs the entire process.
"""
display_logo()
settings: Settings = update_settings()
extract_tracks_from_mkv()
refactor_subtitles()
translate_subtitles(settings)
convert_numbers_to_words()
generate_audio_for_subtitles(settings)
refactor_alt_subtitles()
process_output_files(settings)
clear_temp_folders()
if __name__ == '__main__':
"""
Ensures the main function is only run if the script is executed directly (not imported as a module).
"""
directories: List[str] = [WORKING_SPACE, WORKING_SPACE_OUTPUT,
WORKING_SPACE_TEMP, WORKING_SPACE_TEMP_MAIN_SUBS, WORKING_SPACE_TEMP_ALT_SUBS]
check_and_create_directories(directories)
main()
console.print(
'\n[green_italic]Naciśnij dowolny klawisz, aby zakończyć działanie programu...', end='')
getch()
|