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.
Files changed (237) hide show
  1. subtitld/__init__.py +19 -0
  2. subtitld/__main__.py +240 -0
  3. subtitld/ftfy/char_classes.dat +0 -0
  4. subtitld/graphics/Montserrat-Black.ttf +0 -0
  5. subtitld/graphics/Montserrat-BlackItalic.ttf +0 -0
  6. subtitld/graphics/Montserrat-Bold.ttf +0 -0
  7. subtitld/graphics/Montserrat-BoldItalic.ttf +0 -0
  8. subtitld/graphics/Montserrat-ExtraBold.ttf +0 -0
  9. subtitld/graphics/Montserrat-ExtraBoldItalic.ttf +0 -0
  10. subtitld/graphics/Montserrat-ExtraLight.ttf +0 -0
  11. subtitld/graphics/Montserrat-ExtraLightItalic.ttf +0 -0
  12. subtitld/graphics/Montserrat-Italic.ttf +0 -0
  13. subtitld/graphics/Montserrat-Light.ttf +0 -0
  14. subtitld/graphics/Montserrat-LightItalic.ttf +0 -0
  15. subtitld/graphics/Montserrat-Medium.ttf +0 -0
  16. subtitld/graphics/Montserrat-MediumItalic.ttf +0 -0
  17. subtitld/graphics/Montserrat-Regular.ttf +0 -0
  18. subtitld/graphics/Montserrat-SemiBold.ttf +0 -0
  19. subtitld/graphics/Montserrat-SemiBoldItalic.ttf +0 -0
  20. subtitld/graphics/Montserrat-Thin.ttf +0 -0
  21. subtitld/graphics/Montserrat-ThinItalic.ttf +0 -0
  22. subtitld/graphics/Ubuntu-B.ttf +0 -0
  23. subtitld/graphics/Ubuntu-BI.ttf +0 -0
  24. subtitld/graphics/Ubuntu-C.ttf +0 -0
  25. subtitld/graphics/Ubuntu-L.ttf +0 -0
  26. subtitld/graphics/Ubuntu-LI.ttf +0 -0
  27. subtitld/graphics/Ubuntu-M.ttf +0 -0
  28. subtitld/graphics/Ubuntu-MI.ttf +0 -0
  29. subtitld/graphics/Ubuntu-R.ttf +0 -0
  30. subtitld/graphics/Ubuntu-RI.ttf +0 -0
  31. subtitld/graphics/Ubuntu-Th.ttf +0 -0
  32. subtitld/graphics/UbuntuMono-B.ttf +0 -0
  33. subtitld/graphics/UbuntuMono-BI.ttf +0 -0
  34. subtitld/graphics/UbuntuMono-R.ttf +0 -0
  35. subtitld/graphics/UbuntuMono-RI.ttf +0 -0
  36. subtitld/graphics/add_and_play.svg +4 -0
  37. subtitld/graphics/add_from_last.svg +4 -0
  38. subtitld/graphics/add_from_last_checked.svg +4 -0
  39. subtitld/graphics/add_subtitle_icon.svg +4 -0
  40. subtitld/graphics/add_subtitle_to_next_start.svg +4 -0
  41. subtitld/graphics/add_subtitle_to_next_start_checked.svg +4 -0
  42. subtitld/graphics/background_watermark.svg +9 -0
  43. subtitld/graphics/character_count_icon.svg +1 -0
  44. subtitld/graphics/checkbox_checked.svg +8 -0
  45. subtitld/graphics/checkbox_checked_hover.svg +8 -0
  46. subtitld/graphics/checkbox_disabled.svg +4 -0
  47. subtitld/graphics/checkbox_unchecked.svg +5 -0
  48. subtitld/graphics/checkbox_unchecked_hover.svg +5 -0
  49. subtitld/graphics/combobox_down_arrow.svg +4 -0
  50. subtitld/graphics/cps_icon.svg +1 -0
  51. subtitld/graphics/dialog_close_icon.svg +4 -0
  52. subtitld/graphics/dialog_close_icon_hover.svg +4 -0
  53. subtitld/graphics/dubbing_container_collapse_icon.svg +8 -0
  54. subtitld/graphics/dubbing_container_expand_icon.svg +4 -0
  55. subtitld/graphics/file.svg +4 -0
  56. subtitld/graphics/gap_add_icon.svg +4 -0
  57. subtitld/graphics/gap_remove_icon.svg +4 -0
  58. subtitld/graphics/grid_frames_icon.svg +4 -0
  59. subtitld/graphics/grid_frames_icon_checked.svg +4 -0
  60. subtitld/graphics/grid_frames_icon_disabled.svg +4 -0
  61. subtitld/graphics/grid_scenes_icon.svg +4 -0
  62. subtitld/graphics/grid_scenes_icon_checked.svg +4 -0
  63. subtitld/graphics/grid_scenes_icon_disabled.svg +4 -0
  64. subtitld/graphics/grid_seconds_icon.svg +4 -0
  65. subtitld/graphics/grid_seconds_icon_checked.svg +4 -0
  66. subtitld/graphics/grid_seconds_icon_disabled.svg +4 -0
  67. subtitld/graphics/last_end_to_current_position_icon.svg +4 -0
  68. subtitld/graphics/last_start_last_end_to_current_position_button.svg +9 -0
  69. subtitld/graphics/last_start_to_current_position_icon.svg +4 -0
  70. subtitld/graphics/left_panel_autosave.svg +4 -0
  71. subtitld/graphics/left_panel_dubbing.svg +4 -0
  72. subtitld/graphics/left_panel_export.svg +4 -0
  73. subtitld/graphics/left_panel_global.svg +4 -0
  74. subtitld/graphics/left_panel_import.svg +4 -0
  75. subtitld/graphics/left_panel_interface.svg +4 -0
  76. subtitld/graphics/left_panel_keyboard.svg +4 -0
  77. subtitld/graphics/left_panel_metadata.svg +4 -0
  78. subtitld/graphics/left_panel_navigation_background.svg +11 -0
  79. subtitld/graphics/left_panel_qualitycheck.svg +4 -0
  80. subtitld/graphics/left_panel_speakers.svg +4 -0
  81. subtitld/graphics/left_panel_subtitles.svg +1 -0
  82. subtitld/graphics/left_panel_transcription.svg +4 -0
  83. subtitld/graphics/left_panel_translation.svg +4 -0
  84. subtitld/graphics/merge_back_selected_subtitle_icon.svg +4 -0
  85. subtitld/graphics/merge_next_selected_subtitle_icon.svg +4 -0
  86. subtitld/graphics/move_backward_subtitle.svg +4 -0
  87. subtitld/graphics/move_end_back_subtitle.svg +4 -0
  88. subtitld/graphics/move_end_forward_subtitle.svg +4 -0
  89. subtitld/graphics/move_forward_subtitle.svg +4 -0
  90. subtitld/graphics/move_start_back_subtitle.svg +4 -0
  91. subtitld/graphics/move_start_forward_subtitle.svg +4 -0
  92. subtitld/graphics/music_voice_separation_music_icon.svg +4 -0
  93. subtitld/graphics/music_voice_separation_music_icon_disabled.svg +4 -0
  94. subtitld/graphics/music_voice_separation_voice_icon.svg +4 -0
  95. subtitld/graphics/music_voice_separation_voice_icon_disabled.svg +4 -0
  96. subtitld/graphics/new_line_icon.svg +1 -0
  97. subtitld/graphics/next_end_to_current_position_icon.svg +4 -0
  98. subtitld/graphics/next_start_next_end_to_current_position_button.svg +4 -0
  99. subtitld/graphics/next_start_to_current_position_icon.svg +4 -0
  100. subtitld/graphics/pause_icon.svg +12 -0
  101. subtitld/graphics/play_from_last_start_icon.svg +5 -0
  102. subtitld/graphics/play_from_next_start_icon.svg +7 -0
  103. subtitld/graphics/play_icon.svg +12 -0
  104. subtitld/graphics/play_icon_hover.svg +12 -0
  105. subtitld/graphics/play_icon_pressed.svg +12 -0
  106. subtitld/graphics/playback_repeat.svg +4 -0
  107. subtitld/graphics/playback_speed.svg +6 -0
  108. subtitld/graphics/playbackspeed_border.svg +5 -0
  109. subtitld/graphics/playbackspeed_border_checked.svg +5 -0
  110. subtitld/graphics/playbackspeed_border_hover.svg +5 -0
  111. subtitld/graphics/playercontrols_button_first.svg +5 -0
  112. subtitld/graphics/playercontrols_button_first_hover.svg +6 -0
  113. subtitld/graphics/playercontrols_button_first_pressed.svg +6 -0
  114. subtitld/graphics/playercontrols_button_last.svg +6 -0
  115. subtitld/graphics/playercontrols_button_last_hover.svg +6 -0
  116. subtitld/graphics/playercontrols_button_last_pressed.svg +6 -0
  117. subtitld/graphics/playercontrols_widget_center_bottom_line.svg +13 -0
  118. subtitld/graphics/playercontrols_widget_center_top_line.svg +17 -0
  119. subtitld/graphics/plus_icon.svg +4 -0
  120. subtitld/graphics/record_icon.svg +8 -0
  121. subtitld/graphics/record_icon_pressed.svg +5 -0
  122. subtitld/graphics/remove_selected_subtitle_icon.svg +6 -0
  123. subtitld/graphics/repeat_playback_border.svg +5 -0
  124. subtitld/graphics/repeat_playback_border_checked.svg +5 -0
  125. subtitld/graphics/repeat_playback_border_hover.svg +5 -0
  126. subtitld/graphics/save.svg +4 -0
  127. subtitld/graphics/send_text_to_last_subtitle_and_slice_button.svg +8 -0
  128. subtitld/graphics/send_text_to_last_subtitle_icon.svg +8 -0
  129. subtitld/graphics/send_text_to_next_subtitle_and_slice_button.svg +8 -0
  130. subtitld/graphics/send_text_to_next_subtitle_icon.svg +8 -0
  131. subtitld/graphics/slice_selected_subtitle_icon.svg +4 -0
  132. subtitld/graphics/snap_grid_icon.svg +4 -0
  133. subtitld/graphics/snap_grid_icon_checked.svg +4 -0
  134. subtitld/graphics/snap_grid_icon_disabled.svg +4 -0
  135. subtitld/graphics/snap_limits_icon.svg +4 -0
  136. subtitld/graphics/snap_limits_icon_checked.svg +4 -0
  137. subtitld/graphics/snap_limits_icon_disabled.svg +4 -0
  138. subtitld/graphics/snap_move_next.svg +4 -0
  139. subtitld/graphics/snap_move_next_checked.svg +4 -0
  140. subtitld/graphics/snap_move_next_disabled.svg +4 -0
  141. subtitld/graphics/snap_moving_icon.svg +4 -0
  142. subtitld/graphics/snap_moving_icon_checked.svg +4 -0
  143. subtitld/graphics/snap_moving_icon_disabled.svg +4 -0
  144. subtitld/graphics/speaker_list_item_change_color_icon.svg +4 -0
  145. subtitld/graphics/speaker_list_item_change_color_icon_hover.svg +4 -0
  146. subtitld/graphics/speaker_list_item_change_image_icon.svg +4 -0
  147. subtitld/graphics/speaker_list_item_change_image_icon_hover.svg +4 -0
  148. subtitld/graphics/speaker_list_item_export_icon.svg +4 -0
  149. subtitld/graphics/speaker_list_item_export_icon_hover.svg +4 -0
  150. subtitld/graphics/speaker_list_item_remove_icon.svg +4 -0
  151. subtitld/graphics/speaker_list_item_remove_icon_hover.svg +4 -0
  152. subtitld/graphics/speaker_list_item_rename_icon.svg +4 -0
  153. subtitld/graphics/speaker_list_item_rename_icon_hover.svg +4 -0
  154. subtitld/graphics/spinbox_arrow_down.svg +4 -0
  155. subtitld/graphics/spinbox_arrow_up.svg +4 -0
  156. subtitld/graphics/start_screen_top_shadow.svg +23 -0
  157. subtitld/graphics/stop_icon.svg +6 -0
  158. subtitld/graphics/stop_icon_hover.svg +6 -0
  159. subtitld/graphics/stop_icon_pressed.svg +6 -0
  160. subtitld/graphics/stylesheet.qss +1838 -0
  161. subtitld/graphics/subtitld.ico +0 -0
  162. subtitld/graphics/subtitld.png +0 -0
  163. subtitld/graphics/subtitles_panel_simplelist_properties_duration_timing_lock_closed_icon.svg +4 -0
  164. subtitld/graphics/subtitles_panel_simplelist_properties_duration_timing_lock_open_icon.svg +4 -0
  165. subtitld/graphics/subtitles_panel_simplelist_properties_duration_timing_lock_open_icon_hover.svg +4 -0
  166. subtitld/graphics/timeline_bottom_controls_background.svg +25 -0
  167. subtitld/graphics/timeline_cursor_back_frame.svg +4 -0
  168. subtitld/graphics/timeline_cursor_back_frame_hover.svg +4 -0
  169. subtitld/graphics/timeline_cursor_next_frame.svg +4 -0
  170. subtitld/graphics/timeline_cursor_next_frame_hover.svg +4 -0
  171. subtitld/graphics/timeline_show_speaker_color.svg +5 -0
  172. subtitld/graphics/timeline_show_speaker_color_checked.svg +5 -0
  173. subtitld/graphics/timeline_show_speaker_in_tracks.svg +4 -0
  174. subtitld/graphics/timeline_show_speaker_in_tracks_checked.svg +4 -0
  175. subtitld/graphics/timelinescrolling_follow_icon.svg +4 -0
  176. subtitld/graphics/timelinescrolling_follow_icon_checked.svg +4 -0
  177. subtitld/graphics/timelinescrolling_none_icon.svg +6 -0
  178. subtitld/graphics/timelinescrolling_none_icon_checked.svg +6 -0
  179. subtitld/graphics/timelinescrolling_page_icon.svg +4 -0
  180. subtitld/graphics/timelinescrolling_page_icon_checked.svg +4 -0
  181. subtitld/graphics/titleBar_left_container_border.svg +113 -0
  182. subtitld/graphics/unknown_speaker.svg +5 -0
  183. subtitld/graphics/vosk_transcription_download_model_icon.svg +4 -0
  184. subtitld/graphics/vosk_transcription_update_model_icon.svg +4 -0
  185. subtitld/graphics/word_count_icon.svg +1 -0
  186. subtitld/graphics/wpm_icon.svg +1 -0
  187. subtitld/graphics/zoom_in_icon.svg +4 -0
  188. subtitld/graphics/zoom_in_icon_disabled.svg +4 -0
  189. subtitld/graphics/zoom_out_icon.svg +4 -0
  190. subtitld/graphics/zoom_out_icon_disabled.svg +4 -0
  191. subtitld/interface/__init__.py +0 -0
  192. subtitld/interface/actionmanager.py +18 -0
  193. subtitld/interface/bottom_panel.py +43 -0
  194. subtitld/interface/left_panel.py +144 -0
  195. subtitld/interface/left_panel_autosave.py +149 -0
  196. subtitld/interface/left_panel_dubbing.py +469 -0
  197. subtitld/interface/left_panel_export.py +755 -0
  198. subtitld/interface/left_panel_global.py +358 -0
  199. subtitld/interface/left_panel_import.py +82 -0
  200. subtitld/interface/left_panel_interface.py +616 -0
  201. subtitld/interface/left_panel_keyboard.py +261 -0
  202. subtitld/interface/left_panel_metadata.py +74 -0
  203. subtitld/interface/left_panel_qualitycheck.py +262 -0
  204. subtitld/interface/left_panel_speakers.py +737 -0
  205. subtitld/interface/left_panel_subtitleslist.py +791 -0
  206. subtitld/interface/left_panel_transcription.py +763 -0
  207. subtitld/interface/left_panel_translation.py +294 -0
  208. subtitld/interface/playercontrols.py +2348 -0
  209. subtitld/interface/preview_panel.py +407 -0
  210. subtitld/interface/productionscreen.py +65 -0
  211. subtitld/interface/startscreen.py +273 -0
  212. subtitld/interface/timeline.py +1308 -0
  213. subtitld/interface/top_bar.py +329 -0
  214. subtitld/interface/translation.py +68 -0
  215. subtitld/interface/utils.py +286 -0
  216. subtitld/locale/en_US.json +301 -0
  217. subtitld/locale/pt_BR.json +269 -0
  218. subtitld/modules/__init__.py +0 -0
  219. subtitld/modules/audioengine.py +606 -0
  220. subtitld/modules/bounce.py +229 -0
  221. subtitld/modules/config.py +84 -0
  222. subtitld/modules/file_io.py +870 -0
  223. subtitld/modules/history.py +31 -0
  224. subtitld/modules/quality_check.py +53 -0
  225. subtitld/modules/session.py +270 -0
  226. subtitld/modules/shortcuts.py +84 -0
  227. subtitld/modules/subtitles.py +413 -0
  228. subtitld/modules/timecode.py +496 -0
  229. subtitld/modules/usf.py +366 -0
  230. subtitld/modules/utils.py +79 -0
  231. subtitld/modules/waveform.py +53 -0
  232. subtitld-0.0.0.dev0.dist-info/METADATA +97 -0
  233. subtitld-0.0.0.dev0.dist-info/RECORD +237 -0
  234. subtitld-0.0.0.dev0.dist-info/WHEEL +5 -0
  235. subtitld-0.0.0.dev0.dist-info/entry_points.txt +2 -0
  236. subtitld-0.0.0.dev0.dist-info/licenses/LICENSE +674 -0
  237. subtitld-0.0.0.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,149 @@
1
+ import os
2
+ import subprocess
3
+
4
+ from PySide6.QtWidgets import QVBoxLayout, QWidget, QScrollArea, QCheckBox, QPushButton, QComboBox, QGroupBox, QTabWidget, QGridLayout, QHBoxLayout, QLabel, QSpinBox, QLineEdit, QSizePolicy, QTableWidgetItem, QColorDialog
5
+ from PySide6.QtCore import Qt, QThread, Signal, QSize, QMargins
6
+ from PySide6.QtGui import QPainter, QColor, QPen, QFont, QPixmap, QFontDatabase, QBrush
7
+
8
+ from subtitld.interface import left_panel
9
+ from subtitld.interface.translation import _
10
+ from subtitld.modules import session
11
+ from subtitld.modules import file_io
12
+ from subtitld.modules import utils
13
+ from subtitld.modules import shortcuts
14
+ from subtitld.modules import subtitles
15
+
16
+
17
+ def load(self):
18
+ tab_name = 'autosave'
19
+
20
+ left_panel_autosave_panel = left_panel.left_panel(
21
+ parent=self,
22
+ tab_name=tab_name,
23
+ update_callback=update,
24
+ translate_callback=translate
25
+ )
26
+
27
+ left_panel_autosave_panel_scroll = QScrollArea()
28
+ left_panel_autosave_panel_scroll.setObjectName('left_panel_autosave_panel_scroll')
29
+ left_panel_autosave_panel_scroll.setWidgetResizable(True)
30
+ left_panel_autosave_panel_scroll.setFrameShape(QScrollArea.NoFrame)
31
+ left_panel_autosave_panel.layout().addWidget(left_panel_autosave_panel_scroll)
32
+
33
+ left_panel_autosave_panel_widget = QWidget()
34
+ left_panel_autosave_panel_widget.setProperty('class', 'transparent_panel')
35
+ left_panel_autosave_panel_widget.setObjectName('left_panel_autosave_panel_widget')
36
+ left_panel_autosave_panel_widget.setLayout(QVBoxLayout())
37
+ left_panel_autosave_panel_widget.layout().setContentsMargins(0, 0, 0, 0)
38
+ left_panel_autosave_panel_scroll.setWidget(left_panel_autosave_panel_widget)
39
+
40
+ self.panel_autosave_backup_enabled_checkbox = QCheckBox()
41
+ self.panel_autosave_backup_enabled_checkbox.clicked.connect(lambda: panel_autosave_backup_enabled_checkbox_clicked(self))
42
+ left_panel_autosave_panel_widget.layout().addWidget(self.panel_autosave_backup_enabled_checkbox)
43
+
44
+ self.panel_autosave_backup_interval_row = QWidget()
45
+ self.panel_autosave_backup_interval_row.setLayout(QHBoxLayout())
46
+ self.panel_autosave_backup_interval_row.layout().setContentsMargins(0, 0, 0, 0)
47
+ self.panel_autosave_backup_interval_row.layout().setSpacing(5)
48
+ left_panel_autosave_panel_widget.layout().addWidget(self.panel_autosave_backup_interval_row)
49
+
50
+ self.panel_autosave_backup_interval_label = QLabel()
51
+ self.panel_autosave_backup_interval_row.layout().addWidget(self.panel_autosave_backup_interval_label, 0, Qt.AlignLeft)
52
+
53
+ self.panel_autosave_backup_interval_spinbox = QSpinBox()
54
+ self.panel_autosave_backup_interval_spinbox.setMinimum(1)
55
+ self.panel_autosave_backup_interval_spinbox.setMaximum(1000)
56
+ self.panel_autosave_backup_interval_spinbox.valueChanged.connect(lambda: panel_autosave_backup_interval_spinbox_changed(self))
57
+ self.panel_autosave_backup_interval_row.layout().addWidget(self.panel_autosave_backup_interval_spinbox, 0, Qt.AlignLeft)
58
+
59
+ self.panel_autosave_backup_interval_seconds_label = QLabel()
60
+ self.panel_autosave_backup_interval_seconds_label.setProperty('class', 'units_label')
61
+ self.panel_autosave_backup_interval_row.layout().addWidget(self.panel_autosave_backup_interval_seconds_label, 0, Qt.AlignLeft)
62
+ self.panel_autosave_backup_interval_row.layout().addStretch()
63
+
64
+ self.panel_autosave_original_enabled_checkbox = QCheckBox()
65
+ self.panel_autosave_original_enabled_checkbox.clicked.connect(lambda: panel_autosave_original_enabled_checkbox_clicked(self))
66
+ left_panel_autosave_panel_widget.layout().addWidget(self.panel_autosave_original_enabled_checkbox)
67
+
68
+ self.panel_autosave_original_interval_row = QWidget()
69
+ self.panel_autosave_original_interval_row.setLayout(QHBoxLayout())
70
+ self.panel_autosave_original_interval_row.layout().setContentsMargins(0, 0, 0, 0)
71
+ self.panel_autosave_original_interval_row.layout().setSpacing(5)
72
+ left_panel_autosave_panel_widget.layout().addWidget(self.panel_autosave_original_interval_row)
73
+
74
+ self.panel_autosave_original_interval_label = QLabel()
75
+ self.panel_autosave_original_interval_row.layout().addWidget(self.panel_autosave_original_interval_label, 0, Qt.AlignLeft)
76
+
77
+ self.panel_autosave_original_interval_spinbox = QSpinBox()
78
+ self.panel_autosave_original_interval_spinbox.setMinimum(1)
79
+ self.panel_autosave_original_interval_spinbox.setMaximum(1000)
80
+ self.panel_autosave_original_interval_spinbox.valueChanged.connect(lambda: panel_autosave_original_interval_spinbox_changed(self))
81
+ self.panel_autosave_original_interval_row.layout().addWidget(self.panel_autosave_original_interval_spinbox, 0, Qt.AlignLeft)
82
+
83
+ self.panel_autosave_original_interval_seconds_label = QLabel()
84
+ self.panel_autosave_original_interval_seconds_label.setProperty('class', 'units_label')
85
+ self.panel_autosave_original_interval_row.layout().addWidget(self.panel_autosave_original_interval_seconds_label, 0, Qt.AlignLeft)
86
+ self.panel_autosave_original_interval_row.layout().addStretch()
87
+
88
+ left_panel_autosave_panel_widget.layout().addStretch()
89
+
90
+
91
+ update(self)
92
+
93
+
94
+
95
+ def show(self):
96
+ update(self)
97
+
98
+
99
+ def update(self):
100
+ self.panel_autosave_backup_enabled_checkbox.setChecked(session.CONFIG.get('autosave', {}).get('backup_enabled', True))
101
+ if session.CONFIG.get('autosave', {}).get('backup_enabled', True) and not self.autosave_backup_timer.isActive():
102
+ self.autosave_backup_timer.start()
103
+ else:
104
+ self.autosave_backup_timer.stop()
105
+
106
+ self.panel_autosave_backup_interval_row.setEnabled(session.CONFIG.get('autosave', {}).get('backup_enabled', True))
107
+ self.panel_autosave_backup_interval_spinbox.setValue(session.CONFIG.get('autosave', {}).get('backup_interval', 300000) / (60 * 1000))
108
+
109
+ self.panel_autosave_original_enabled_checkbox.setChecked(session.CONFIG.get('autosave', {}).get('original_enabled', True))
110
+ if session.CONFIG.get('autosave', {}).get('original_enabled', True) and not self.autosave_original_timer.isActive():
111
+ self.autosave_original_timer.start()
112
+ else:
113
+ self.autosave_original_timer.stop()
114
+
115
+ self.panel_autosave_original_interval_row.setEnabled(session.CONFIG.get('autosave', {}).get('original_enabled', True))
116
+ self.panel_autosave_original_interval_spinbox.setValue(session.CONFIG.get('autosave', {}).get('original_interval', 300000) / (60 * 1000))
117
+
118
+ def hide(self):
119
+ pass
120
+
121
+
122
+ def panel_autosave_original_enabled_checkbox_clicked(self):
123
+ session.CONFIG['autosave']['original_enabled'] = self.panel_autosave_original_enabled_checkbox.isChecked()
124
+ update(self)
125
+
126
+ def panel_autosave_original_interval_spinbox_changed(self):
127
+ session.CONFIG['autosave']['original_interval'] = self.panel_autosave_original_interval_spinbox.value() * 60 * 1000
128
+ update(self)
129
+
130
+
131
+ def panel_autosave_backup_enabled_checkbox_clicked(self):
132
+ session.CONFIG['autosave']['backup_enabled'] = self.panel_autosave_backup_enabled_checkbox.isChecked()
133
+ update(self)
134
+
135
+ def panel_autosave_backup_interval_spinbox_changed(self):
136
+ session.CONFIG['autosave']['backup_interval'] = self.panel_autosave_backup_interval_spinbox.value() * 60 * 1000
137
+ update(self)
138
+
139
+
140
+ def translate(self):
141
+ self.panel_autosave_backup_enabled_checkbox.setText(_('autosave_panel.autosave_backup_enable'))
142
+ self.panel_autosave_backup_interval_label.setText(_('autosave_panel.autosave_backup_interval'))
143
+ self.panel_autosave_backup_interval_seconds_label.setText(_('units.minutes'))
144
+ self.panel_autosave_original_enabled_checkbox.setText(_('autosave_panel.autosave_original_enable'))
145
+ self.panel_autosave_original_interval_label.setText(_('autosave_panel.autosave_original_interval'))
146
+ self.panel_autosave_original_interval_seconds_label.setText(_('units.minutes'))
147
+
148
+
149
+
@@ -0,0 +1,469 @@
1
+ import os
2
+ import secrets
3
+ import asyncio
4
+ import edge_tts
5
+
6
+ from PySide6.QtWidgets import QStackedWidget, QWidget, QVBoxLayout, QHBoxLayout, QSpinBox, QPushButton, QLabel, QLineEdit, QSizePolicy, QColorDialog, QComboBox, QCheckBox, QApplication
7
+ from PySide6.QtGui import QImage, QPixmap, QPainter, QPainterPath, QColor
8
+ from PySide6.QtCore import QThread, QObject, Signal, Qt, QSize
9
+
10
+ from subtitld.interface import utils
11
+ from subtitld.interface import left_panel
12
+ from subtitld.interface.translation import _
13
+
14
+ from subtitld.modules import session
15
+ from subtitld.modules import subtitles
16
+
17
+
18
+ class _EdgeTTSSignals(QObject):
19
+ speech_ready = Signal(str, dict, str) # (uid, output_file)
20
+ speech_error = Signal(str, str) # (uid, message)
21
+ voices_updated = Signal()
22
+
23
+
24
+ class _EdgeTTSSpeechThread(QThread):
25
+ speech_ready = Signal(str, dict, str)
26
+ speech_error = Signal(str, str)
27
+
28
+ def __init__(self, text_list):
29
+ super().__init__()
30
+ self.text_list = text_list
31
+
32
+ def run(self):
33
+ loop = asyncio.new_event_loop()
34
+ asyncio.set_event_loop(loop)
35
+
36
+ cache_dir = os.path.join(session.PATH_SUBTITLD_USER_CACHE, 'dubbing')
37
+ if not os.path.exists(cache_dir):
38
+ os.makedirs(cache_dir)
39
+
40
+ for subtitle in self.text_list:
41
+ output_file = os.path.join(cache_dir, f'{subtitle["uid"]}.wav')
42
+ try:
43
+ loop.run_until_complete(self._generate(subtitle, output_file))
44
+ self.speech_ready.emit(subtitle['uid'], subtitle, output_file)
45
+ except Exception as e:
46
+ self.speech_error.emit(subtitle['uid'], str(e))
47
+
48
+ loop.close()
49
+
50
+ async def _generate(self, subtitle, final_file):
51
+ speaker = session.SPEAKERS.get(subtitle['speaker'], {}).get('dubbing', {})
52
+ voice = subtitle.get('voice') or speaker.get('voice', '')
53
+ communicate = edge_tts.Communicate(
54
+ text=subtitle['text'],
55
+ voice=voice,
56
+ rate=f'{subtitle.get("rate", 0):+d}%',
57
+ pitch=f'{subtitle.get("pitch", 0):+d}Hz',
58
+ )
59
+ await communicate.save(final_file)
60
+
61
+
62
+ class _EdgeTTSVoicesThread(QThread):
63
+ voice_received = Signal(dict)
64
+
65
+ def run(self):
66
+ voices = asyncio.run(edge_tts.list_voices())
67
+ for v in voices:
68
+ self.voice_received.emit(v)
69
+
70
+
71
+ class EdgeTTSEngine:
72
+ signals = _EdgeTTSSignals()
73
+ _speech_threads = []
74
+ _voices_thread = None
75
+
76
+ @staticmethod
77
+ def get_voices_list():
78
+ if EdgeTTSEngine._voices_thread is not None:
79
+ return
80
+
81
+ session.CONFIG['dubbing'].setdefault('edge-tts', {}).setdefault('voices', {})
82
+
83
+ def on_voice(voice):
84
+ session.CONFIG['dubbing']['edge-tts']['voices'][voice['ShortName']] = voice
85
+
86
+ def on_finished():
87
+ EdgeTTSEngine._voices_thread = None
88
+ EdgeTTSEngine.signals.voices_updated.emit()
89
+
90
+ thread = _EdgeTTSVoicesThread()
91
+ thread.voice_received.connect(on_voice)
92
+ thread.finished.connect(on_finished)
93
+ EdgeTTSEngine._voices_thread = thread
94
+ thread.start()
95
+
96
+ @staticmethod
97
+ def generate_speeches(text_list):
98
+ thread = _EdgeTTSSpeechThread(text_list)
99
+ thread.speech_ready.connect(EdgeTTSEngine.signals.speech_ready)
100
+ thread.speech_error.connect(EdgeTTSEngine.signals.speech_error)
101
+ thread.finished.connect(lambda: EdgeTTSEngine._speech_threads.remove(thread))
102
+ EdgeTTSEngine._speech_threads.append(thread)
103
+ thread.start()
104
+
105
+ @staticmethod
106
+ def _on_speech_ready(uid, original_subtitle, file_path):
107
+ for subtitle in session.SUBTITLE['segments']:
108
+ if subtitle.get('start') == original_subtitle['start']:
109
+ dubs = subtitle.setdefault('dubbing', [])
110
+ inherited_start = dubs[0].get('start', subtitle['start']) if dubs else subtitle['start']
111
+ dubs.insert(0, {
112
+ 'engine': 'edge-tts',
113
+ 'path': file_path,
114
+ 'start': inherited_start,
115
+ 'end': subtitle['end'],
116
+ 'uid': uid,
117
+ 'rate': original_subtitle.get('rate', 0),
118
+ 'pitch': original_subtitle.get('pitch', 0),
119
+ })
120
+ break
121
+ for window in QApplication.topLevelWidgets():
122
+ preview = getattr(window, 'preview_panel_player', None)
123
+ timeline_widget = getattr(window, 'timeline_widget', None)
124
+ if preview is None and timeline_widget is None:
125
+ continue
126
+ if preview is not None:
127
+ preview._audio_device.sync_subtitle_dubs(session.SUBTITLE['segments'])
128
+ if timeline_widget is not None:
129
+ timeline_widget.update()
130
+ session.set_unsaved()
131
+ break
132
+
133
+ class speaker_panel(QWidget):
134
+ def __init__(widget, parent=None):
135
+ super().__init__(parent=None)
136
+ widget.parent = parent
137
+ widget.setLayout(QVBoxLayout())
138
+ widget.layout().setContentsMargins(5, 5, 5, 5)
139
+ widget.layout().setSpacing(5)
140
+ widget.setProperty('dubbing_engine', 'edge-tts')
141
+ widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
142
+ widget.setProperty('class', 'transparent_panel')
143
+
144
+ if not 'edge-tts' in session.CONFIG['dubbing']:
145
+ session.CONFIG['dubbing']['edge-tts'] = {}
146
+
147
+ if not 'voices' in session.CONFIG['dubbing']['edge-tts'] or not session.CONFIG['dubbing']['edge-tts']['voices']:
148
+ EdgeTTSEngine.get_voices_list()
149
+
150
+ widget.voice_combobox = utils.LabeledComboBox()
151
+ widget.voice_combobox.addItems(session.CONFIG['dubbing']['edge-tts']['voices'].keys())
152
+ widget.voice_combobox.activated.connect(lambda: widget.voice_combobox_changed())
153
+ widget.layout().addWidget(widget.voice_combobox)
154
+
155
+ settings_line = QHBoxLayout()
156
+ widget.voice_rate_label = QLabel()
157
+ settings_line.addWidget(widget.voice_rate_label)
158
+ widget.voice_rate = QSpinBox()
159
+ widget.voice_rate.setMinimum(-100)
160
+ widget.voice_rate.setMaximum(100)
161
+ widget.voice_rate.setValue(0)
162
+ widget.voice_rate.valueChanged.connect(lambda: widget.voice_rate_changed())
163
+ settings_line.addWidget(widget.voice_rate)
164
+ settings_line.addSpacing(10)
165
+
166
+ widget.voice_pitch_label = QLabel()
167
+ settings_line.addWidget(widget.voice_pitch_label)
168
+ widget.voice_pitch = QSpinBox()
169
+ widget.voice_pitch.setMinimum(-100)
170
+ widget.voice_pitch.setMaximum(100)
171
+ widget.voice_pitch.setValue(0)
172
+ widget.voice_pitch.valueChanged.connect(lambda: widget.voice_pitch_changed())
173
+ settings_line.addWidget(widget.voice_pitch)
174
+ settings_line.addStretch()
175
+
176
+ widget.layout().addLayout(settings_line)
177
+
178
+ widget.generate_all_speeches_button = QPushButton()
179
+ widget.generate_all_speeches_button.clicked.connect(lambda: widget.generate_all_speeches_button_clicked())
180
+ widget.layout().addWidget(widget.generate_all_speeches_button, 0, Qt.AlignRight)
181
+
182
+ EdgeTTSEngine.signals.voices_updated.connect(widget._refresh_voices)
183
+ EdgeTTSEngine.signals.speech_error.connect(widget._on_speech_error)
184
+
185
+ widget.update()
186
+
187
+ def _refresh_voices(widget):
188
+ current = widget.voice_combobox.currentText()
189
+ widget.voice_combobox.clear()
190
+ widget.voice_combobox.addItems(session.CONFIG['dubbing']['edge-tts']['voices'].keys())
191
+ if current:
192
+ widget.voice_combobox.setCurrentText(current)
193
+
194
+ def _on_speech_error(widget, uid, message):
195
+ print('edge-tts error:', uid, message)
196
+
197
+ def voice_combobox_changed(widget):
198
+ value = widget.voice_combobox.currentText()
199
+ speaker_name = widget.property('speaker')
200
+ if speaker_name and speaker_name in session.SPEAKERS:
201
+ session.SPEAKERS[speaker_name]['dubbing']['voice'] = value
202
+
203
+ def voice_rate_changed(widget):
204
+ value = widget.voice_rate.value()
205
+ speaker_name = widget.property('speaker')
206
+ if speaker_name and speaker_name in session.SPEAKERS:
207
+ session.SPEAKERS[speaker_name]['dubbing']['rate'] = value
208
+
209
+ def voice_pitch_changed(widget):
210
+ value = widget.voice_pitch.value()
211
+ speaker_name = widget.property('speaker')
212
+ if speaker_name and speaker_name in session.SPEAKERS:
213
+ session.SPEAKERS[speaker_name]['dubbing']['pitch'] = value
214
+
215
+ def generate_all_speeches_button_clicked(widget):
216
+ speaker_name = widget.property('speaker')
217
+ speaker_dubbing = session.SPEAKERS.get(speaker_name, {}).get('dubbing', {})
218
+ speeches_to_generate = []
219
+ for subtitle in session.SUBTITLE['segments']:
220
+ if subtitle.get('speaker', 'A') == speaker_name:
221
+ overrides = subtitle.get('dubbing_options', {})
222
+ speeches_to_generate.append({
223
+ 'uid': secrets.token_hex(4),
224
+ 'text': subtitle['text'],
225
+ 'speaker': speaker_name,
226
+ 'start': subtitle['start'],
227
+ 'end': subtitle['end'],
228
+ 'voice': overrides.get('voice') or speaker_dubbing.get('voice', ''),
229
+ 'rate': overrides.get('rate', speaker_dubbing.get('rate', 0)),
230
+ 'pitch': overrides.get('pitch', speaker_dubbing.get('pitch', 0)),
231
+ })
232
+ if speeches_to_generate:
233
+ EdgeTTSEngine.generate_speeches(speeches_to_generate)
234
+
235
+ def update(widget):
236
+ speaker_name = widget.property('speaker')
237
+ dubbing = session.SPEAKERS.get(speaker_name, {}).get('dubbing') if speaker_name else None
238
+ if not isinstance(dubbing, dict):
239
+ dubbing = {}
240
+
241
+ widget.voice_combobox.combobox.blockSignals(True)
242
+ widget.voice_combobox.setCurrentText(dubbing.get('voice', ''))
243
+ widget.voice_combobox.combobox.blockSignals(False)
244
+
245
+ widget.voice_rate.blockSignals(True)
246
+ widget.voice_rate.setValue(int(dubbing.get('rate', 0) or 0))
247
+ widget.voice_rate.blockSignals(False)
248
+
249
+ widget.voice_pitch.blockSignals(True)
250
+ widget.voice_pitch.setValue(int(dubbing.get('pitch', 0) or 0))
251
+ widget.voice_pitch.blockSignals(False)
252
+
253
+ def translate(widget):
254
+ widget.voice_combobox.setLabel(_('subtitles_panel_widget_dubbing.voice'))
255
+ widget.voice_rate_label.setText(_('subtitles_panel_widget_dubbing.rate'))
256
+ widget.voice_pitch_label.setText(_('subtitles_panel_widget_dubbing.pitch'))
257
+ widget.generate_all_speeches_button.setText(_('subtitles_panel_widget_dubbing.generate_all_speeches'))
258
+
259
+ class dubbingPanel(QWidget):
260
+ def __init__(widget, parent=None):
261
+ super().__init__(parent=None)
262
+ widget.parent = parent
263
+ widget.setLayout(QVBoxLayout())
264
+ widget.layout().setContentsMargins(0, 0, 0, 0)
265
+ widget.layout().setSpacing(10)
266
+ widget.setProperty('dubbing_engine', 'edge-tts')
267
+ widget.setProperty('class', 'transparent_panel')
268
+
269
+ widget.no_subtitle_label = QLabel()
270
+ widget.no_subtitle_label.setWordWrap(True)
271
+ widget.no_subtitle_label.setAlignment(Qt.AlignCenter)
272
+ widget.layout().addWidget(widget.no_subtitle_label)
273
+
274
+ widget.settings_container = QWidget()
275
+ widget.settings_container.setLayout(QVBoxLayout())
276
+ widget.settings_container.layout().setContentsMargins(0, 0, 0, 0)
277
+ widget.settings_container.layout().setSpacing(5)
278
+ widget.layout().addWidget(widget.settings_container)
279
+
280
+ widget.voice_combobox = utils.LabeledComboBox()
281
+ widget.voice_combobox.addItems(session.CONFIG.get('dubbing', {}).get('edge-tts', {}).get('voices', {}).keys())
282
+ widget.voice_combobox.activated.connect(lambda: widget.voice_combobox_changed())
283
+ widget.settings_container.layout().addWidget(widget.voice_combobox)
284
+
285
+ settings_line = QHBoxLayout()
286
+ widget.voice_rate_label = QLabel()
287
+ settings_line.addWidget(widget.voice_rate_label)
288
+ widget.voice_rate = QSpinBox()
289
+ widget.voice_rate.setMinimum(-100)
290
+ widget.voice_rate.setMaximum(100)
291
+ widget.voice_rate.valueChanged.connect(lambda: widget.voice_rate_changed())
292
+ settings_line.addWidget(widget.voice_rate)
293
+ settings_line.addSpacing(10)
294
+
295
+ widget.voice_pitch_label = QLabel()
296
+ settings_line.addWidget(widget.voice_pitch_label)
297
+ widget.voice_pitch = QSpinBox()
298
+ widget.voice_pitch.setMinimum(-100)
299
+ widget.voice_pitch.setMaximum(100)
300
+ widget.voice_pitch.valueChanged.connect(lambda: widget.voice_pitch_changed())
301
+ settings_line.addWidget(widget.voice_pitch)
302
+ settings_line.addStretch()
303
+ widget.settings_container.layout().addLayout(settings_line)
304
+
305
+ widget.generate_speech_button = QPushButton()
306
+ widget.generate_speech_button.clicked.connect(lambda: widget.generate_speech_button_clicked())
307
+ widget.settings_container.layout().addWidget(widget.generate_speech_button, 0, Qt.AlignRight)
308
+
309
+ EdgeTTSEngine.signals.voices_updated.connect(widget._refresh_voices)
310
+
311
+ widget.update_callback = widget.update
312
+ widget.translate_callback = widget.translate
313
+
314
+ def _refresh_voices(widget):
315
+ current = widget.voice_combobox.currentText()
316
+ widget.voice_combobox.clear()
317
+ widget.voice_combobox.addItems(session.CONFIG.get('dubbing', {}).get('edge-tts', {}).get('voices', {}).keys())
318
+ if current:
319
+ widget.voice_combobox.setCurrentText(current)
320
+
321
+ def voice_combobox_changed(widget):
322
+ selected = session.SUBTITLE.get('selected')
323
+ if selected is None:
324
+ return
325
+ selected.setdefault('dubbing_options', {})['voice'] = widget.voice_combobox.currentText()
326
+ session.set_unsaved()
327
+
328
+ def voice_rate_changed(widget):
329
+ selected = session.SUBTITLE.get('selected')
330
+ if selected is None:
331
+ return
332
+ selected.setdefault('dubbing_options', {})['rate'] = widget.voice_rate.value()
333
+ session.set_unsaved()
334
+
335
+ def voice_pitch_changed(widget):
336
+ selected = session.SUBTITLE.get('selected')
337
+ if selected is None:
338
+ return
339
+ selected.setdefault('dubbing_options', {})['pitch'] = widget.voice_pitch.value()
340
+ session.set_unsaved()
341
+
342
+ def generate_speech_button_clicked(widget):
343
+ selected = session.SUBTITLE.get('selected')
344
+ if not selected:
345
+ return
346
+ speaker_name = selected.get('speaker', 'A')
347
+ speaker_dubbing = session.SPEAKERS.get(speaker_name, {}).get('dubbing', {})
348
+ overrides = selected.get('dubbing_options', {})
349
+ EdgeTTSEngine.generate_speeches([{
350
+ 'uid': secrets.token_hex(4),
351
+ 'text': selected['text'],
352
+ 'speaker': speaker_name,
353
+ 'start': selected['start'],
354
+ 'end': selected['end'],
355
+ 'voice': overrides.get('voice') or speaker_dubbing.get('voice', ''),
356
+ 'rate': overrides.get('rate', speaker_dubbing.get('rate', 0)),
357
+ 'pitch': overrides.get('pitch', speaker_dubbing.get('pitch', 0)),
358
+ }])
359
+
360
+ def update(widget):
361
+ selected = session.SUBTITLE.get('selected')
362
+ if not selected:
363
+ widget.no_subtitle_label.setVisible(True)
364
+ widget.settings_container.setVisible(False)
365
+ return
366
+ widget.no_subtitle_label.setVisible(False)
367
+ widget.settings_container.setVisible(True)
368
+
369
+ speaker_dubbing = session.SPEAKERS.get(selected.get('speaker', 'A'), {}).get('dubbing', {})
370
+ overrides = selected.get('dubbing_options', {})
371
+
372
+ effective_voice = overrides.get('voice') or speaker_dubbing.get('voice', '')
373
+ effective_rate = overrides.get('rate', speaker_dubbing.get('rate', 0))
374
+ effective_pitch = overrides.get('pitch', speaker_dubbing.get('pitch', 0))
375
+
376
+ widget.voice_combobox.combobox.blockSignals(True)
377
+ widget.voice_combobox.setCurrentText(effective_voice)
378
+ widget.voice_combobox.combobox.blockSignals(False)
379
+
380
+ widget.voice_rate.blockSignals(True)
381
+ widget.voice_rate.setValue(int(effective_rate or 0))
382
+ widget.voice_rate.blockSignals(False)
383
+
384
+ widget.voice_pitch.blockSignals(True)
385
+ widget.voice_pitch.setValue(int(effective_pitch or 0))
386
+ widget.voice_pitch.blockSignals(False)
387
+
388
+ def translate(widget):
389
+ widget.no_subtitle_label.setText(_('subtitles_panel_widget_dubbing.no_subtitle_selected'))
390
+ widget.voice_combobox.setLabel(_('subtitles_panel_widget_dubbing.voice'))
391
+ widget.voice_rate_label.setText(_('subtitles_panel_widget_dubbing.rate'))
392
+ widget.voice_pitch_label.setText(_('subtitles_panel_widget_dubbing.pitch'))
393
+ widget.generate_speech_button.setText(_('subtitles_panel_widget_dubbing.generate_speech'))
394
+
395
+
396
+ EdgeTTSEngine.signals.speech_ready.connect(EdgeTTSEngine._on_speech_ready)
397
+
398
+
399
+ def load(self):
400
+ tab_name = 'dubbing'
401
+
402
+ left_panel_dubbing_panel = left_panel.left_panel(
403
+ parent=self,
404
+ tab_name=tab_name,
405
+ update_callback=update,
406
+ translate_callback=translate
407
+ )
408
+
409
+ self.left_panel_dubbing_enable_checkbox = QCheckBox()
410
+ self.left_panel_dubbing_enable_checkbox.setObjectName('left_panel_dubbing_enable_checkbox')
411
+ self.left_panel_dubbing_enable_checkbox.clicked.connect(lambda: left_panel_dubbing_enable_checkbox_clicked(self))
412
+ left_panel_dubbing_panel.layout().addWidget(self.left_panel_dubbing_enable_checkbox)
413
+
414
+ self.left_panel_dubbing_engine_combobox = utils.LabeledComboBox()
415
+ self.left_panel_dubbing_engine_combobox.setProperty('class', 'button')
416
+ self.left_panel_dubbing_engine_combobox.activated.connect(lambda: left_panel_dubbing_engine_combobox_activated(self))
417
+ left_panel_dubbing_panel.layout().addWidget(self.left_panel_dubbing_engine_combobox)
418
+
419
+ self.global_panel_dubbing_tabwidget = QStackedWidget()
420
+ self.global_panel_dubbing_tabwidget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
421
+
422
+ global_panel_dubbing_edgetts_engine = EdgeTTSEngine
423
+ self.global_panel_dubbing_tabwidget.addWidget(global_panel_dubbing_edgetts_engine.dubbingPanel())
424
+ self.left_panel_speakers_list_of_available_dubbing_engine['edge-tts'] = global_panel_dubbing_edgetts_engine
425
+ self.left_panel_dubbing_engine_combobox.addItem('edge-tts')
426
+
427
+ left_panel_dubbing_panel.layout().addWidget(self.global_panel_dubbing_tabwidget)
428
+ left_panel_dubbing_panel.layout().addStretch()
429
+
430
+ update(self)
431
+
432
+
433
+ def left_panel_dubbing_enable_checkbox_clicked(self):
434
+ session.CONFIG['dubbing']['enabled'] = self.left_panel_dubbing_enable_checkbox.isChecked()
435
+
436
+
437
+ def left_panel_dubbing_engine_combobox_activated(self):
438
+ session.CONFIG['dubbing']['selected_engine'] = self.left_panel_dubbing_engine_combobox.currentText()
439
+ global_panel_dubbing_tabwidget_update(self)
440
+
441
+
442
+ def update(self):
443
+ self.left_panel_dubbing_enable_checkbox.setChecked(session.CONFIG['dubbing'].get('enabled', False))
444
+ self.left_panel_dubbing_engine_combobox.setCurrentText(session.CONFIG['dubbing'].get('selected_engine', 'edge-tts'))
445
+
446
+ selected_engine = self.left_panel_dubbing_engine_combobox.currentText()
447
+ for widget in self.global_panel_dubbing_tabwidget.findChildren(QWidget):
448
+ if widget.property('dubbing_engine') == selected_engine and hasattr(widget, 'update_callback'):
449
+ widget.update_callback()
450
+ break
451
+
452
+
453
+ def translate(self):
454
+ self.left_panel_dubbing_enable_checkbox.setText(_('subtitles_panel_widget_dubbing.enable_dubbing'))
455
+ self.left_panel_dubbing_engine_combobox.setLabel(_('subtitles_panel_widget_dubbing.engine'))
456
+ for widget in self.global_panel_dubbing_tabwidget.findChildren(QWidget):
457
+ if widget.property('dubbing_engine') == self.left_panel_dubbing_engine_combobox.currentText():
458
+ widget.translate_callback()
459
+ break
460
+
461
+
462
+
463
+ def global_panel_dubbing_tabwidget_update(self):
464
+ for widget in self.global_panel_dubbing_tabwidget.findChildren(QWidget):
465
+ if widget.property('dubbing_engine') == self.left_panel_dubbing_engine_combobox.currentText():
466
+ self.global_panel_dubbing_tabwidget.setCurrentWidget(widget)
467
+ widget.update_callback()
468
+ break
469
+