subtitld 0.0.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- subtitld/__init__.py +19 -0
- subtitld/__main__.py +240 -0
- subtitld/ftfy/char_classes.dat +0 -0
- subtitld/graphics/Montserrat-Black.ttf +0 -0
- subtitld/graphics/Montserrat-BlackItalic.ttf +0 -0
- subtitld/graphics/Montserrat-Bold.ttf +0 -0
- subtitld/graphics/Montserrat-BoldItalic.ttf +0 -0
- subtitld/graphics/Montserrat-ExtraBold.ttf +0 -0
- subtitld/graphics/Montserrat-ExtraBoldItalic.ttf +0 -0
- subtitld/graphics/Montserrat-ExtraLight.ttf +0 -0
- subtitld/graphics/Montserrat-ExtraLightItalic.ttf +0 -0
- subtitld/graphics/Montserrat-Italic.ttf +0 -0
- subtitld/graphics/Montserrat-Light.ttf +0 -0
- subtitld/graphics/Montserrat-LightItalic.ttf +0 -0
- subtitld/graphics/Montserrat-Medium.ttf +0 -0
- subtitld/graphics/Montserrat-MediumItalic.ttf +0 -0
- subtitld/graphics/Montserrat-Regular.ttf +0 -0
- subtitld/graphics/Montserrat-SemiBold.ttf +0 -0
- subtitld/graphics/Montserrat-SemiBoldItalic.ttf +0 -0
- subtitld/graphics/Montserrat-Thin.ttf +0 -0
- subtitld/graphics/Montserrat-ThinItalic.ttf +0 -0
- subtitld/graphics/Ubuntu-B.ttf +0 -0
- subtitld/graphics/Ubuntu-BI.ttf +0 -0
- subtitld/graphics/Ubuntu-C.ttf +0 -0
- subtitld/graphics/Ubuntu-L.ttf +0 -0
- subtitld/graphics/Ubuntu-LI.ttf +0 -0
- subtitld/graphics/Ubuntu-M.ttf +0 -0
- subtitld/graphics/Ubuntu-MI.ttf +0 -0
- subtitld/graphics/Ubuntu-R.ttf +0 -0
- subtitld/graphics/Ubuntu-RI.ttf +0 -0
- subtitld/graphics/Ubuntu-Th.ttf +0 -0
- subtitld/graphics/UbuntuMono-B.ttf +0 -0
- subtitld/graphics/UbuntuMono-BI.ttf +0 -0
- subtitld/graphics/UbuntuMono-R.ttf +0 -0
- subtitld/graphics/UbuntuMono-RI.ttf +0 -0
- subtitld/graphics/add_and_play.svg +4 -0
- subtitld/graphics/add_from_last.svg +4 -0
- subtitld/graphics/add_from_last_checked.svg +4 -0
- subtitld/graphics/add_subtitle_icon.svg +4 -0
- subtitld/graphics/add_subtitle_to_next_start.svg +4 -0
- subtitld/graphics/add_subtitle_to_next_start_checked.svg +4 -0
- subtitld/graphics/background_watermark.svg +9 -0
- subtitld/graphics/character_count_icon.svg +1 -0
- subtitld/graphics/checkbox_checked.svg +8 -0
- subtitld/graphics/checkbox_checked_hover.svg +8 -0
- subtitld/graphics/checkbox_disabled.svg +4 -0
- subtitld/graphics/checkbox_unchecked.svg +5 -0
- subtitld/graphics/checkbox_unchecked_hover.svg +5 -0
- subtitld/graphics/combobox_down_arrow.svg +4 -0
- subtitld/graphics/cps_icon.svg +1 -0
- subtitld/graphics/dialog_close_icon.svg +4 -0
- subtitld/graphics/dialog_close_icon_hover.svg +4 -0
- subtitld/graphics/dubbing_container_collapse_icon.svg +8 -0
- subtitld/graphics/dubbing_container_expand_icon.svg +4 -0
- subtitld/graphics/file.svg +4 -0
- subtitld/graphics/gap_add_icon.svg +4 -0
- subtitld/graphics/gap_remove_icon.svg +4 -0
- subtitld/graphics/grid_frames_icon.svg +4 -0
- subtitld/graphics/grid_frames_icon_checked.svg +4 -0
- subtitld/graphics/grid_frames_icon_disabled.svg +4 -0
- subtitld/graphics/grid_scenes_icon.svg +4 -0
- subtitld/graphics/grid_scenes_icon_checked.svg +4 -0
- subtitld/graphics/grid_scenes_icon_disabled.svg +4 -0
- subtitld/graphics/grid_seconds_icon.svg +4 -0
- subtitld/graphics/grid_seconds_icon_checked.svg +4 -0
- subtitld/graphics/grid_seconds_icon_disabled.svg +4 -0
- subtitld/graphics/last_end_to_current_position_icon.svg +4 -0
- subtitld/graphics/last_start_last_end_to_current_position_button.svg +9 -0
- subtitld/graphics/last_start_to_current_position_icon.svg +4 -0
- subtitld/graphics/left_panel_autosave.svg +4 -0
- subtitld/graphics/left_panel_dubbing.svg +4 -0
- subtitld/graphics/left_panel_export.svg +4 -0
- subtitld/graphics/left_panel_global.svg +4 -0
- subtitld/graphics/left_panel_import.svg +4 -0
- subtitld/graphics/left_panel_interface.svg +4 -0
- subtitld/graphics/left_panel_keyboard.svg +4 -0
- subtitld/graphics/left_panel_metadata.svg +4 -0
- subtitld/graphics/left_panel_navigation_background.svg +11 -0
- subtitld/graphics/left_panel_qualitycheck.svg +4 -0
- subtitld/graphics/left_panel_speakers.svg +4 -0
- subtitld/graphics/left_panel_subtitles.svg +1 -0
- subtitld/graphics/left_panel_transcription.svg +4 -0
- subtitld/graphics/left_panel_translation.svg +4 -0
- subtitld/graphics/merge_back_selected_subtitle_icon.svg +4 -0
- subtitld/graphics/merge_next_selected_subtitle_icon.svg +4 -0
- subtitld/graphics/move_backward_subtitle.svg +4 -0
- subtitld/graphics/move_end_back_subtitle.svg +4 -0
- subtitld/graphics/move_end_forward_subtitle.svg +4 -0
- subtitld/graphics/move_forward_subtitle.svg +4 -0
- subtitld/graphics/move_start_back_subtitle.svg +4 -0
- subtitld/graphics/move_start_forward_subtitle.svg +4 -0
- subtitld/graphics/music_voice_separation_music_icon.svg +4 -0
- subtitld/graphics/music_voice_separation_music_icon_disabled.svg +4 -0
- subtitld/graphics/music_voice_separation_voice_icon.svg +4 -0
- subtitld/graphics/music_voice_separation_voice_icon_disabled.svg +4 -0
- subtitld/graphics/new_line_icon.svg +1 -0
- subtitld/graphics/next_end_to_current_position_icon.svg +4 -0
- subtitld/graphics/next_start_next_end_to_current_position_button.svg +4 -0
- subtitld/graphics/next_start_to_current_position_icon.svg +4 -0
- subtitld/graphics/pause_icon.svg +12 -0
- subtitld/graphics/play_from_last_start_icon.svg +5 -0
- subtitld/graphics/play_from_next_start_icon.svg +7 -0
- subtitld/graphics/play_icon.svg +12 -0
- subtitld/graphics/play_icon_hover.svg +12 -0
- subtitld/graphics/play_icon_pressed.svg +12 -0
- subtitld/graphics/playback_repeat.svg +4 -0
- subtitld/graphics/playback_speed.svg +6 -0
- subtitld/graphics/playbackspeed_border.svg +5 -0
- subtitld/graphics/playbackspeed_border_checked.svg +5 -0
- subtitld/graphics/playbackspeed_border_hover.svg +5 -0
- subtitld/graphics/playercontrols_button_first.svg +5 -0
- subtitld/graphics/playercontrols_button_first_hover.svg +6 -0
- subtitld/graphics/playercontrols_button_first_pressed.svg +6 -0
- subtitld/graphics/playercontrols_button_last.svg +6 -0
- subtitld/graphics/playercontrols_button_last_hover.svg +6 -0
- subtitld/graphics/playercontrols_button_last_pressed.svg +6 -0
- subtitld/graphics/playercontrols_widget_center_bottom_line.svg +13 -0
- subtitld/graphics/playercontrols_widget_center_top_line.svg +17 -0
- subtitld/graphics/plus_icon.svg +4 -0
- subtitld/graphics/record_icon.svg +8 -0
- subtitld/graphics/record_icon_pressed.svg +5 -0
- subtitld/graphics/remove_selected_subtitle_icon.svg +6 -0
- subtitld/graphics/repeat_playback_border.svg +5 -0
- subtitld/graphics/repeat_playback_border_checked.svg +5 -0
- subtitld/graphics/repeat_playback_border_hover.svg +5 -0
- subtitld/graphics/save.svg +4 -0
- subtitld/graphics/send_text_to_last_subtitle_and_slice_button.svg +8 -0
- subtitld/graphics/send_text_to_last_subtitle_icon.svg +8 -0
- subtitld/graphics/send_text_to_next_subtitle_and_slice_button.svg +8 -0
- subtitld/graphics/send_text_to_next_subtitle_icon.svg +8 -0
- subtitld/graphics/slice_selected_subtitle_icon.svg +4 -0
- subtitld/graphics/snap_grid_icon.svg +4 -0
- subtitld/graphics/snap_grid_icon_checked.svg +4 -0
- subtitld/graphics/snap_grid_icon_disabled.svg +4 -0
- subtitld/graphics/snap_limits_icon.svg +4 -0
- subtitld/graphics/snap_limits_icon_checked.svg +4 -0
- subtitld/graphics/snap_limits_icon_disabled.svg +4 -0
- subtitld/graphics/snap_move_next.svg +4 -0
- subtitld/graphics/snap_move_next_checked.svg +4 -0
- subtitld/graphics/snap_move_next_disabled.svg +4 -0
- subtitld/graphics/snap_moving_icon.svg +4 -0
- subtitld/graphics/snap_moving_icon_checked.svg +4 -0
- subtitld/graphics/snap_moving_icon_disabled.svg +4 -0
- subtitld/graphics/speaker_list_item_change_color_icon.svg +4 -0
- subtitld/graphics/speaker_list_item_change_color_icon_hover.svg +4 -0
- subtitld/graphics/speaker_list_item_change_image_icon.svg +4 -0
- subtitld/graphics/speaker_list_item_change_image_icon_hover.svg +4 -0
- subtitld/graphics/speaker_list_item_export_icon.svg +4 -0
- subtitld/graphics/speaker_list_item_export_icon_hover.svg +4 -0
- subtitld/graphics/speaker_list_item_remove_icon.svg +4 -0
- subtitld/graphics/speaker_list_item_remove_icon_hover.svg +4 -0
- subtitld/graphics/speaker_list_item_rename_icon.svg +4 -0
- subtitld/graphics/speaker_list_item_rename_icon_hover.svg +4 -0
- subtitld/graphics/spinbox_arrow_down.svg +4 -0
- subtitld/graphics/spinbox_arrow_up.svg +4 -0
- subtitld/graphics/start_screen_top_shadow.svg +23 -0
- subtitld/graphics/stop_icon.svg +6 -0
- subtitld/graphics/stop_icon_hover.svg +6 -0
- subtitld/graphics/stop_icon_pressed.svg +6 -0
- subtitld/graphics/stylesheet.qss +1838 -0
- subtitld/graphics/subtitld.ico +0 -0
- subtitld/graphics/subtitld.png +0 -0
- subtitld/graphics/subtitles_panel_simplelist_properties_duration_timing_lock_closed_icon.svg +4 -0
- subtitld/graphics/subtitles_panel_simplelist_properties_duration_timing_lock_open_icon.svg +4 -0
- subtitld/graphics/subtitles_panel_simplelist_properties_duration_timing_lock_open_icon_hover.svg +4 -0
- subtitld/graphics/timeline_bottom_controls_background.svg +25 -0
- subtitld/graphics/timeline_cursor_back_frame.svg +4 -0
- subtitld/graphics/timeline_cursor_back_frame_hover.svg +4 -0
- subtitld/graphics/timeline_cursor_next_frame.svg +4 -0
- subtitld/graphics/timeline_cursor_next_frame_hover.svg +4 -0
- subtitld/graphics/timeline_show_speaker_color.svg +5 -0
- subtitld/graphics/timeline_show_speaker_color_checked.svg +5 -0
- subtitld/graphics/timeline_show_speaker_in_tracks.svg +4 -0
- subtitld/graphics/timeline_show_speaker_in_tracks_checked.svg +4 -0
- subtitld/graphics/timelinescrolling_follow_icon.svg +4 -0
- subtitld/graphics/timelinescrolling_follow_icon_checked.svg +4 -0
- subtitld/graphics/timelinescrolling_none_icon.svg +6 -0
- subtitld/graphics/timelinescrolling_none_icon_checked.svg +6 -0
- subtitld/graphics/timelinescrolling_page_icon.svg +4 -0
- subtitld/graphics/timelinescrolling_page_icon_checked.svg +4 -0
- subtitld/graphics/titleBar_left_container_border.svg +113 -0
- subtitld/graphics/unknown_speaker.svg +5 -0
- subtitld/graphics/vosk_transcription_download_model_icon.svg +4 -0
- subtitld/graphics/vosk_transcription_update_model_icon.svg +4 -0
- subtitld/graphics/word_count_icon.svg +1 -0
- subtitld/graphics/wpm_icon.svg +1 -0
- subtitld/graphics/zoom_in_icon.svg +4 -0
- subtitld/graphics/zoom_in_icon_disabled.svg +4 -0
- subtitld/graphics/zoom_out_icon.svg +4 -0
- subtitld/graphics/zoom_out_icon_disabled.svg +4 -0
- subtitld/interface/__init__.py +0 -0
- subtitld/interface/actionmanager.py +18 -0
- subtitld/interface/bottom_panel.py +43 -0
- subtitld/interface/left_panel.py +144 -0
- subtitld/interface/left_panel_autosave.py +149 -0
- subtitld/interface/left_panel_dubbing.py +469 -0
- subtitld/interface/left_panel_export.py +755 -0
- subtitld/interface/left_panel_global.py +358 -0
- subtitld/interface/left_panel_import.py +82 -0
- subtitld/interface/left_panel_interface.py +616 -0
- subtitld/interface/left_panel_keyboard.py +261 -0
- subtitld/interface/left_panel_metadata.py +74 -0
- subtitld/interface/left_panel_qualitycheck.py +262 -0
- subtitld/interface/left_panel_speakers.py +737 -0
- subtitld/interface/left_panel_subtitleslist.py +791 -0
- subtitld/interface/left_panel_transcription.py +763 -0
- subtitld/interface/left_panel_translation.py +294 -0
- subtitld/interface/playercontrols.py +2348 -0
- subtitld/interface/preview_panel.py +407 -0
- subtitld/interface/productionscreen.py +65 -0
- subtitld/interface/startscreen.py +273 -0
- subtitld/interface/timeline.py +1308 -0
- subtitld/interface/top_bar.py +329 -0
- subtitld/interface/translation.py +68 -0
- subtitld/interface/utils.py +286 -0
- subtitld/locale/en_US.json +301 -0
- subtitld/locale/pt_BR.json +269 -0
- subtitld/modules/__init__.py +0 -0
- subtitld/modules/audioengine.py +606 -0
- subtitld/modules/bounce.py +229 -0
- subtitld/modules/config.py +84 -0
- subtitld/modules/file_io.py +870 -0
- subtitld/modules/history.py +31 -0
- subtitld/modules/quality_check.py +53 -0
- subtitld/modules/session.py +270 -0
- subtitld/modules/shortcuts.py +84 -0
- subtitld/modules/subtitles.py +413 -0
- subtitld/modules/timecode.py +496 -0
- subtitld/modules/usf.py +366 -0
- subtitld/modules/utils.py +79 -0
- subtitld/modules/waveform.py +53 -0
- subtitld-0.0.0.dev0.dist-info/METADATA +97 -0
- subtitld-0.0.0.dev0.dist-info/RECORD +237 -0
- subtitld-0.0.0.dev0.dist-info/WHEEL +5 -0
- subtitld-0.0.0.dev0.dist-info/entry_points.txt +2 -0
- subtitld-0.0.0.dev0.dist-info/licenses/LICENSE +674 -0
- subtitld-0.0.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""History module (Ctrl+Z)
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
|
|
7
|
+
from subtitld.modules import session
|
|
8
|
+
|
|
9
|
+
ALL_HISTORY = []
|
|
10
|
+
REDO_HISTORY = []
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def history_append(subtitles):
|
|
14
|
+
"""Append subtitles list to history"""
|
|
15
|
+
ALL_HISTORY.append(copy.deepcopy(subtitles))
|
|
16
|
+
REDO_HISTORY.clear()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def history_undo():
|
|
20
|
+
"""Revert to last subtitle on the history list"""
|
|
21
|
+
if ALL_HISTORY:
|
|
22
|
+
REDO_HISTORY.append(copy.deepcopy(session.SUBTITLE['segments']))
|
|
23
|
+
session.SUBTITLE['segments'].clear()
|
|
24
|
+
session.SUBTITLE['segments'].extend(copy.deepcopy(ALL_HISTORY.pop()))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def history_redo():
|
|
28
|
+
"""Redo subtitle on the history list"""
|
|
29
|
+
if REDO_HISTORY:
|
|
30
|
+
session.SUBTITLE['segments'].clear()
|
|
31
|
+
session.SUBTITLE['segments'].extend(copy.deepcopy(REDO_HISTORY.pop()))
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Module to check subtitles quality
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from subtitld.modules import session
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def check_subtitle(subtitle=[]):
|
|
9
|
+
"""Function to check individual subtitle"""
|
|
10
|
+
approved = True
|
|
11
|
+
reasons = []
|
|
12
|
+
issues = []
|
|
13
|
+
|
|
14
|
+
settings = session.CONFIG.get('quality_check', {})
|
|
15
|
+
|
|
16
|
+
if subtitle and (subtitle['end'] - subtitle['start']):
|
|
17
|
+
if len(subtitle['text'].replace('\n', '')) / (subtitle['end'] - subtitle['start']) > settings.get('reading_speed_cps', 21):
|
|
18
|
+
approved = False
|
|
19
|
+
reasons.append('Reading speed: {ars} characters per second. It should be {rs} per second.'.format(rs=settings.get('reading_speed_cps', 21), ars=round(len(subtitle['text'].replace('\n', '')) / (subtitle['end'] - subtitle['start']), 2)))
|
|
20
|
+
issues.append('cps')
|
|
21
|
+
if len(subtitle['text'].replace('\n', '').split(' ')) / ((subtitle['end'] - subtitle['start']) / 60) > settings.get('reading_speed_wpm', 140):
|
|
22
|
+
approved = False
|
|
23
|
+
reasons.append('Reading speed: {ars} words per minute. It should be {rs} per minute.'.format(rs=settings.get('reading_speed_wpm', 140), ars=round(len(subtitle['text'].replace('\n', '').split(' ')) / ((subtitle['end'] - subtitle['start']) / 60))))
|
|
24
|
+
issues.append('wpm')
|
|
25
|
+
if (subtitle['end'] - subtitle['start']) < settings.get('minimum_duration', .7):
|
|
26
|
+
approved = False
|
|
27
|
+
reasons.append('The duration of this subtitle, {ad}, is less than the minimum of {d}.'.format(d=settings.get('minimum_duration', .7), ad=round((subtitle['end'] - subtitle['start']), 2)))
|
|
28
|
+
issues.append('duration')
|
|
29
|
+
if (subtitle['end'] - subtitle['start']) > settings.get('maximum_duration', 7):
|
|
30
|
+
approved = False
|
|
31
|
+
reasons.append('The duration of this subtitle, {ad}, is more than the maximum of {d}.'.format(d=settings.get('maximum_duration', 7), ad=round((subtitle['end'] - subtitle['start']), 2)))
|
|
32
|
+
issues.append('duration')
|
|
33
|
+
if len(subtitle['text'].split('\n')) > settings.get('maximum_lines', 2):
|
|
34
|
+
approved = False
|
|
35
|
+
reasons.append('There are {al} lines, more than the maximum of {l}.'.format(l=settings.get('maximum_lines', 2), al=round(len(subtitle['text'].split('\n')), 2)))
|
|
36
|
+
issues.append('number_of_lines')
|
|
37
|
+
for line in subtitle['text'].split('\n'):
|
|
38
|
+
if len(line) > settings.get('maximum_characters_per_line', 42):
|
|
39
|
+
approved = False
|
|
40
|
+
reasons.append('There are more than {c} characters per line ({ac}).'.format(c=settings.get('maximum_characters_per_line', 42), ac=len(line)))
|
|
41
|
+
issues.append('cpl')
|
|
42
|
+
break
|
|
43
|
+
if len(subtitle['text'].split('\n')) > 1:
|
|
44
|
+
if settings.get('prefer_compact', False):
|
|
45
|
+
if len(subtitle['text'].replace('\n', '')) < settings.get('maximum_characters_per_line', 42):
|
|
46
|
+
approved = False
|
|
47
|
+
reasons.append('The lines should be joined as there are less than {c} characters in total.'.format(c=settings.get('maximum_characters_per_line', 42)))
|
|
48
|
+
if settings.get('balance_ratio_enabled', False):
|
|
49
|
+
if len(min(subtitle['text'].split('\n'), key=len)) < len(max(subtitle['text'].split('\n'), key=len))*(settings.get('balance_ratio', 50)/100):
|
|
50
|
+
approved = False
|
|
51
|
+
reasons.append('The shortest line length is less than {p}% the largest.'.format(p=settings.get('balance_ratio', 50)))
|
|
52
|
+
|
|
53
|
+
return approved, reasons, issues
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""All path definitions for Subtitld"""
|
|
2
|
+
|
|
3
|
+
import pathlib
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
import subprocess
|
|
7
|
+
import subtitld
|
|
8
|
+
import platformdirs
|
|
9
|
+
|
|
10
|
+
PATH_SUBTITLD = pathlib.Path(subtitld.__file__).parent
|
|
11
|
+
PATH_HOME = pathlib.Path.home()
|
|
12
|
+
PATH_LOCALE = PATH_SUBTITLD / 'locale'
|
|
13
|
+
PATH_SUBTITLD_GRAPHICS = PATH_SUBTITLD / 'graphics'
|
|
14
|
+
PATH_SUBTITLD_USER_CONFIG = pathlib.Path(platformdirs.user_config_dir('subtitld'))
|
|
15
|
+
PATH_SUBTITLD_USER_CACHE = pathlib.Path(platformdirs.user_cache_dir('subtitld'))
|
|
16
|
+
FFMPEG_EXECUTABLE = 'ffmpeg'
|
|
17
|
+
FFPROBE_EXECUTABLE = 'ffprobe'
|
|
18
|
+
STARTUPINFO = None
|
|
19
|
+
|
|
20
|
+
ACTUAL_OS = 'linux'
|
|
21
|
+
|
|
22
|
+
tempdir = tempfile.TemporaryDirectory()
|
|
23
|
+
PATH_TEMP = tempdir.name
|
|
24
|
+
|
|
25
|
+
if sys.platform == 'darwin':
|
|
26
|
+
ACTUAL_OS = 'macos'
|
|
27
|
+
if getattr(sys, "frozen", False):
|
|
28
|
+
FFMPEG_EXECUTABLE = str(pathlib.Path(PATH_SUBTITLD).parent / 'ffmpeg')
|
|
29
|
+
FFPROBE_EXECUTABLE = str(pathlib.Path(PATH_SUBTITLD).parent / 'ffprobe')
|
|
30
|
+
elif sys.platform == 'win32':
|
|
31
|
+
ACTUAL_OS = 'windows'
|
|
32
|
+
|
|
33
|
+
if getattr(sys, "frozen", False):
|
|
34
|
+
FFMPEG_EXECUTABLE = pathlib.Path(PATH_SUBTITLD).parent / 'ffmpeg.exe'
|
|
35
|
+
FFPROBE_EXECUTABLE = pathlib.Path(PATH_SUBTITLD).parent / 'ffprobe.exe'
|
|
36
|
+
else:
|
|
37
|
+
script_dir = pathlib.Path(sys.argv[0]).parent
|
|
38
|
+
FFMPEG_EXECUTABLE = script_dir / 'ffmpeg.exe'
|
|
39
|
+
FFPROBE_EXECUTABLE = script_dir / 'ffprobe.exe'
|
|
40
|
+
STARTUPINFO = subprocess.STARTUPINFO()
|
|
41
|
+
STARTUPINFO.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
42
|
+
STARTUPINFO.wShowWindow = subprocess.SW_HIDE
|
|
43
|
+
import multiprocessing
|
|
44
|
+
multiprocessing.freeze_support()
|
|
45
|
+
else:
|
|
46
|
+
# Linux (AppImage, Snap, Flatpak, pip install). When frozen by
|
|
47
|
+
# PyInstaller we ship ffmpeg/ffprobe next to the main executable;
|
|
48
|
+
# for regular installs we fall back to whatever the distro provides.
|
|
49
|
+
if getattr(sys, "frozen", False):
|
|
50
|
+
FFMPEG_EXECUTABLE = str(pathlib.Path(PATH_SUBTITLD).parent / 'ffmpeg')
|
|
51
|
+
FFPROBE_EXECUTABLE = str(pathlib.Path(PATH_SUBTITLD).parent / 'ffprobe')
|
|
52
|
+
|
|
53
|
+
if not PATH_SUBTITLD_USER_CONFIG.exists():
|
|
54
|
+
PATH_SUBTITLD_USER_CONFIG.mkdir(parents=True)
|
|
55
|
+
|
|
56
|
+
if not PATH_SUBTITLD_USER_CACHE.exists():
|
|
57
|
+
PATH_SUBTITLD_USER_CACHE.mkdir(parents=True)
|
|
58
|
+
|
|
59
|
+
PATH_SUBTITLD_DATA_BACKUP = PATH_SUBTITLD_USER_CACHE / 'backup'
|
|
60
|
+
|
|
61
|
+
if not PATH_SUBTITLD_DATA_BACKUP.exists():
|
|
62
|
+
PATH_SUBTITLD_DATA_BACKUP.mkdir(parents=True)
|
|
63
|
+
|
|
64
|
+
PATH_SUBTITLD_DATA_MODELS = PATH_SUBTITLD_USER_CACHE / 'models'
|
|
65
|
+
|
|
66
|
+
if not PATH_SUBTITLD_DATA_MODELS.exists():
|
|
67
|
+
PATH_SUBTITLD_DATA_MODELS.mkdir(parents=True)
|
|
68
|
+
|
|
69
|
+
PATH_SUBTITLD_DATA_AUDIOSEPARATION = PATH_SUBTITLD_USER_CACHE / 'audioseparation'
|
|
70
|
+
|
|
71
|
+
if not PATH_SUBTITLD_DATA_AUDIOSEPARATION.exists():
|
|
72
|
+
PATH_SUBTITLD_DATA_AUDIOSEPARATION.mkdir(parents=True)
|
|
73
|
+
|
|
74
|
+
PATH_SUBTITLD_USER_CONFIG_FILE = PATH_SUBTITLD_USER_CONFIG / 'subtitld.config'
|
|
75
|
+
|
|
76
|
+
# VERSION_NUMBER = '20.07.0.0'
|
|
77
|
+
# if os.path.isfile(os.path.join(PATH_SUBTITLD, 'current_version')):
|
|
78
|
+
# VERSION_NUMBER = open(os.path.join(PATH_SUBTITLD, 'current_version')).read().strip()
|
|
79
|
+
|
|
80
|
+
LIST_OF_SUPPORTED_VIDEO_EXTENSIONS = {
|
|
81
|
+
'MP4': {'description': 'MPEG-4 Video format', 'extensions': ['mp4']},
|
|
82
|
+
'MKV': {'description': 'Matroska Video format', 'extensions': ['mkv']},
|
|
83
|
+
'MOV': {'description': 'Quicktime Video format', 'extensions': ['mov']},
|
|
84
|
+
'MPG': {'description': 'MPEG Video format', 'extensions': ['mpg']},
|
|
85
|
+
'WEBM': {'description': 'WebM Video format', 'extensions': ['webm']},
|
|
86
|
+
'OGV': {'description': 'Ogg Video format', 'extensions': ['ogv']},
|
|
87
|
+
'M4V': {'description': 'MPEG-4 Video format', 'extensions': ['m4v']},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
LIST_OF_SUPPORTED_SUBTITLE_EXTENSIONS = {
|
|
91
|
+
'SRT': {'description': 'SubRip Subtitle format', 'extensions': ['srt']},
|
|
92
|
+
'DFXP': {'description': 'DFXP ITT Subtitle format', 'extensions': ['dfxp', 'itt']},
|
|
93
|
+
'TTML': {'description': 'TTML Subtitle format', 'extensions': ['ttml']},
|
|
94
|
+
'SAMI': {'description': 'SAMI Subtitle format', 'extensions': ['smi', 'sami']},
|
|
95
|
+
'SCC': {'description': 'SCC Subtitle format', 'extensions': ['scc']},
|
|
96
|
+
'VTT': {'description': 'VTT Subtitle format', 'extensions': ['webvtt', 'vtt']},
|
|
97
|
+
'ASS': {'description': 'SubStation Alpha Subtitle format', 'extensions': ['ass', 'ssa']},
|
|
98
|
+
'SBV': {'description': 'SBV Subtitle format', 'extensions': ['sbv']},
|
|
99
|
+
'SUB': {'description': 'MicroDVD Subtitle format', 'extensions': ['sub']},
|
|
100
|
+
'XML': {'description': 'XML Subtitle format', 'extensions': ['xml']},
|
|
101
|
+
'USF': {'description': 'Universal Subtitle Format', 'extensions': ['usf']},
|
|
102
|
+
'USFX': {'description': 'Universal Subtitle Format bundled with assets', 'extensions': ['usfx']},
|
|
103
|
+
'JSON': {'description': 'JSON format', 'extensions': ['json']},
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
LIST_OF_SUPPORTED_IMPORT_EXTENSIONS = {
|
|
107
|
+
'TXT': {'description': 'Simple TXT file', 'extensions': ['txt']},
|
|
108
|
+
'DOCX': {'description': 'Microsoft Word document (docx)', 'extensions': ['docx']},
|
|
109
|
+
'SRT': {'description': 'SubRip Subtitle format', 'extensions': ['srt']}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
LIST_OF_SUPPORTED_EXPORT_EXTENSIONS = {
|
|
113
|
+
'TXT': {'description': 'Simple TXT file', 'extensions': ['txt']},
|
|
114
|
+
'KDENLIVE': {'description': 'Kdenlive format', 'extensions': ['kdenlive']}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
LIST_OF_SUPPORTED_AUDIO_EXPORT_EXTENSIONS = {
|
|
118
|
+
'WAV': {'description': 'WAV audio', 'extensions': ['wav']},
|
|
119
|
+
'FLAC': {'description': 'FLAC lossless audio', 'extensions': ['flac']},
|
|
120
|
+
'MP3': {'description': 'MP3 audio', 'extensions': ['mp3']},
|
|
121
|
+
'MP4': {'description': 'MP4 video with dubbed audio', 'extensions': ['mp4']},
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
LANGUAGE_DICT_LIST = {
|
|
125
|
+
'Afrikaans (South Africa)': 'af-za',
|
|
126
|
+
'Amharic (Ethiopia)': 'am-et',
|
|
127
|
+
'Arabic (United Arab Emirates)': 'ar-ae',
|
|
128
|
+
'Arabic (Bahrain)': 'ar-bh',
|
|
129
|
+
'Arabic (Algeria)': 'ar-dz',
|
|
130
|
+
'Arabic (Egypt)': 'ar-eg',
|
|
131
|
+
'Arabic (Israel)': 'ar-il',
|
|
132
|
+
'Arabic (Iraq)': 'ar-iq',
|
|
133
|
+
'Arabic (Jordan)': 'ar-jo',
|
|
134
|
+
'Arabic (Kuwait)': 'ar-kw',
|
|
135
|
+
'Arabic (Lebanon)': 'ar-lb',
|
|
136
|
+
'Arabic (Morocco)': 'ar-ma',
|
|
137
|
+
'Arabic (Oman)': 'ar-om',
|
|
138
|
+
'Arabic (State of Palestine)': 'ar-ps',
|
|
139
|
+
'Arabic (Qatar)': 'ar-qa',
|
|
140
|
+
'Arabic (Saudi Arabia)': 'ar-sa',
|
|
141
|
+
'Arabic (Tunisia)': 'ar-tn',
|
|
142
|
+
'Azerbaijani (Azerbaijan)': 'az-az',
|
|
143
|
+
'Bulgarian (Bulgaria)': 'bg-bg',
|
|
144
|
+
'Bengali (Bangladesh)': 'bn-bd',
|
|
145
|
+
'Bengali (India)': 'bn-in',
|
|
146
|
+
'Catalan (Spain)': 'ca-es',
|
|
147
|
+
'Chinese, Mandarin (Simplified, China)': 'cmn-hans-cn',
|
|
148
|
+
'Chinese, Mandarin (Simplified, Hong Kong)': 'cmn-hans-hk',
|
|
149
|
+
'Chinese, Mandarin (Traditional, Taiwan)': 'cmn-hant-tw',
|
|
150
|
+
'Czech (Czech Republic)': 'cs-cz',
|
|
151
|
+
'Danish (Denmark)': 'da-dk',
|
|
152
|
+
'German (Germany)': 'de-de',
|
|
153
|
+
'Greek (Greece)': 'el-gr',
|
|
154
|
+
'English (Australia)': 'en-au',
|
|
155
|
+
'English (Canada)': 'en-ca',
|
|
156
|
+
'English (United Kingdom)': 'en-gb',
|
|
157
|
+
'English (Ghana)': 'en-gh',
|
|
158
|
+
'English (Ireland)': 'en-ie',
|
|
159
|
+
'English (India)': 'en-in',
|
|
160
|
+
'English (Kenya)': 'en-ke',
|
|
161
|
+
'English (Nigeria)': 'en-ng',
|
|
162
|
+
'English (New Zealand)': 'en-nz',
|
|
163
|
+
'English (Philippines)': 'en-ph',
|
|
164
|
+
'English (Singapore)': 'en-sg',
|
|
165
|
+
'English (Tanzania)': 'en-tz',
|
|
166
|
+
'English (United States)': 'en-us',
|
|
167
|
+
'English (South Africa)': 'en-za',
|
|
168
|
+
'Spanish (Argentina)': 'es-ar',
|
|
169
|
+
'Spanish (Bolivia)': 'es-bo',
|
|
170
|
+
'Spanish (Chile)': 'es-cl',
|
|
171
|
+
'Spanish (Colombia)': 'es-co',
|
|
172
|
+
'Spanish (Costa Rica)': 'es-cr',
|
|
173
|
+
'Spanish (Dominican Republic)': 'es-do',
|
|
174
|
+
'Spanish (Ecuador)': 'es-ec',
|
|
175
|
+
'Spanish (Spain)': 'es-es',
|
|
176
|
+
'Spanish (Guatemala)': 'es-gt',
|
|
177
|
+
'Spanish (Honduras)': 'es-hn',
|
|
178
|
+
'Spanish (Mexico)': 'es-mx',
|
|
179
|
+
'Spanish (Nicaragua)': 'es-ni',
|
|
180
|
+
'Spanish (Panama)': 'es-pa',
|
|
181
|
+
'Spanish (Peru)': 'es-pe',
|
|
182
|
+
'Spanish (Puerto Rico)': 'es-pr',
|
|
183
|
+
'Spanish (Paraguay)': 'es-py',
|
|
184
|
+
'Spanish (El Salvador)': 'es-sv',
|
|
185
|
+
'Spanish (United States)': 'es-us',
|
|
186
|
+
'Spanish (Uruguay)': 'es-uy',
|
|
187
|
+
'Spanish (Venezuela)': 'es-ve',
|
|
188
|
+
'Basque (Spain)': 'eu-es',
|
|
189
|
+
'Persian (Iran)': 'fa-ir',
|
|
190
|
+
'Finnish (Finland)': 'fi-fi',
|
|
191
|
+
'Filipino (Philippines)': 'fil-ph',
|
|
192
|
+
'French (Canada)': 'fr-ca',
|
|
193
|
+
'French (France)': 'fr-fr',
|
|
194
|
+
'Galician (Spain)': 'gl-es',
|
|
195
|
+
'Gujarati (India)': 'gu-in',
|
|
196
|
+
'Hebrew (Israel)': 'he-il',
|
|
197
|
+
'Hindi (India)': 'hi-in',
|
|
198
|
+
'Croatian (Croatia)': 'hr-hr',
|
|
199
|
+
'Hungarian (Hungary)': 'hu-hu',
|
|
200
|
+
'Armenian (Armenia)': 'hy-am',
|
|
201
|
+
'Indonesian (Indonesia)': 'id-id',
|
|
202
|
+
'Icelandic (Iceland)': 'is-is',
|
|
203
|
+
'Italian (Italy)': 'it-it',
|
|
204
|
+
'Japanese (Japan)': 'ja-jp',
|
|
205
|
+
'Javanese (Indonesia)': 'jv-id',
|
|
206
|
+
'Georgian (Georgia)': 'ka-ge',
|
|
207
|
+
'Khmer (Cambodia)': 'km-kh',
|
|
208
|
+
'Kannada (India)': 'kn-in',
|
|
209
|
+
'Korean (South Korea)': 'ko-kr',
|
|
210
|
+
'Lao (Laos)': 'lo-la',
|
|
211
|
+
'Lithuanian (Lithuania)': 'lt-lt',
|
|
212
|
+
'Latvian (Latvia)': 'lv-lv',
|
|
213
|
+
'Malayalam (India)': 'ml-in',
|
|
214
|
+
'Marathi (India)': 'mr-in',
|
|
215
|
+
'Malay (Malaysia)': 'ms-my',
|
|
216
|
+
'Norwegian Bokmal (Norway)': 'nb-no',
|
|
217
|
+
'Nepali (Nepal)': 'ne-np',
|
|
218
|
+
'Dutch (Netherlands)': 'nl-nl',
|
|
219
|
+
'Polish (Poland)': 'pl-pl',
|
|
220
|
+
'Portuguese (Brazil)': 'pt-br',
|
|
221
|
+
'Portuguese (Portugal)': 'pt-pt',
|
|
222
|
+
'Romanian (Romania)': 'ro-ro',
|
|
223
|
+
'Russian (Russia)': 'ru-ru',
|
|
224
|
+
'Sinhala (Sri Lanka)': 'si-lk',
|
|
225
|
+
'Slovak (Slovakia)': 'sk-sk',
|
|
226
|
+
'Slovenian (Slovenia)': 'sl-si',
|
|
227
|
+
'Serbian (Serbia)': 'sr-rs',
|
|
228
|
+
'Sundanese (Indonesia)': 'su-id',
|
|
229
|
+
'Swedish (Sweden)': 'sv-se',
|
|
230
|
+
'Swahili (Kenya)': 'sw-ke',
|
|
231
|
+
'Swahili (Tanzania)': 'sw-tz',
|
|
232
|
+
'Tamil (India)': 'ta-in',
|
|
233
|
+
'Tamil (Sri Lanka)': 'ta-lk',
|
|
234
|
+
'Tamil (Malaysia)': 'ta-my',
|
|
235
|
+
'Tamil (Singapore)': 'ta-sg',
|
|
236
|
+
'Telugu (India)': 'te-in',
|
|
237
|
+
'Thai (Thailand)': 'th-th',
|
|
238
|
+
'Turkish (Turkey)': 'tr-tr',
|
|
239
|
+
'Ukrainian (Ukraine)': 'uk-ua',
|
|
240
|
+
'Urdu (India)': 'ur-in',
|
|
241
|
+
'Urdu (Pakistan)': 'ur-pk',
|
|
242
|
+
'Vietnamese (Vietnam)': 'vi-vn',
|
|
243
|
+
'Chinese, Cantonese (Traditional, Hong Kong)': 'yue-hant-hk',
|
|
244
|
+
'Zulu (South Africa)': 'zu-za'
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
CONFIG = {}
|
|
248
|
+
|
|
249
|
+
SUBTITLE = {
|
|
250
|
+
'segments': [],
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
SPEAKERS = {}
|
|
254
|
+
|
|
255
|
+
VIDEO = {}
|
|
256
|
+
|
|
257
|
+
FORMAT = {}
|
|
258
|
+
|
|
259
|
+
REPEAT_DURATION_BUFFER = []
|
|
260
|
+
|
|
261
|
+
UNSAVED = False
|
|
262
|
+
_unsaved_change_callbacks = []
|
|
263
|
+
def set_unsaved(value=True):
|
|
264
|
+
global UNSAVED
|
|
265
|
+
old_value = UNSAVED
|
|
266
|
+
UNSAVED = value
|
|
267
|
+
if old_value != value:
|
|
268
|
+
for callback in _unsaved_change_callbacks:
|
|
269
|
+
callback()
|
|
270
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Shortcuts module - Robust customizable shortcut system with decorators
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from PySide6.QtGui import QAction
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ShortcutRegistry:
|
|
9
|
+
"""Registry for managing shortcuts and their associated actions"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self._shortcuts = {}
|
|
13
|
+
|
|
14
|
+
def register(self, command_id, description, default_keys, handler):
|
|
15
|
+
"""Register a shortcut with its handler"""
|
|
16
|
+
self._shortcuts[command_id] = {
|
|
17
|
+
'description': description,
|
|
18
|
+
'default_keys': default_keys,
|
|
19
|
+
'handler': handler
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def shortcut(self, command_id, description, keys):
|
|
23
|
+
"""Decorator to register a function as a shortcut handler
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
@shortcut('my_command', 'My Command Description', ['Ctrl+K'])
|
|
27
|
+
def my_handler(self):
|
|
28
|
+
# handler code
|
|
29
|
+
"""
|
|
30
|
+
def decorator(func):
|
|
31
|
+
self.register(command_id, description, keys, func)
|
|
32
|
+
return func
|
|
33
|
+
return decorator
|
|
34
|
+
|
|
35
|
+
def get_description(self, command_id):
|
|
36
|
+
return self._shortcuts.get(command_id, {}).get('description', '')
|
|
37
|
+
|
|
38
|
+
def get_default_keys(self, command_id):
|
|
39
|
+
return self._shortcuts.get(command_id, {}).get('default_keys', [])
|
|
40
|
+
|
|
41
|
+
def get_handler(self, command_id):
|
|
42
|
+
return self._shortcuts.get(command_id, {}).get('handler')
|
|
43
|
+
|
|
44
|
+
def get_all_commands(self):
|
|
45
|
+
return list(self._shortcuts.keys())
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Global registry
|
|
49
|
+
_registry = ShortcutRegistry()
|
|
50
|
+
shortcut = _registry.shortcut
|
|
51
|
+
|
|
52
|
+
# Legacy compatibility
|
|
53
|
+
shortcuts_dict = {}
|
|
54
|
+
default_shortcuts_dict = {}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def load(self, shortcut_commands):
|
|
58
|
+
"""Load shortcuts commands on widgets"""
|
|
59
|
+
# Update legacy dicts
|
|
60
|
+
shortcuts_dict.update({cmd: _registry.get_description(cmd) for cmd in _registry.get_all_commands()})
|
|
61
|
+
default_shortcuts_dict.update({cmd: _registry.get_default_keys(cmd) for cmd in _registry.get_all_commands()})
|
|
62
|
+
|
|
63
|
+
for command_id in _registry.get_all_commands():
|
|
64
|
+
if command_id not in shortcut_commands:
|
|
65
|
+
shortcut_commands[command_id] = _registry.get_default_keys(command_id)
|
|
66
|
+
|
|
67
|
+
for command_id, keys in shortcut_commands.items():
|
|
68
|
+
handler = _registry.get_handler(command_id)
|
|
69
|
+
if handler:
|
|
70
|
+
action = QAction(_registry.get_description(command_id), self)
|
|
71
|
+
action.setShortcuts(keys)
|
|
72
|
+
action.triggered.connect(lambda checked=False, h=handler: h(self))
|
|
73
|
+
self.addAction(action)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def disable_actions(self):
|
|
77
|
+
for action in self.actions():
|
|
78
|
+
action.setEnabled(False)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def enable_actions(self):
|
|
82
|
+
for action in self.actions():
|
|
83
|
+
action.setEnabled(True)
|
|
84
|
+
|