Allows choosing and managing each tool

This commit is contained in:
Guillaume Tâche
2024-10-03 21:55:14 +02:00
parent 0a2f9e0c31
commit df58cf4585
117 changed files with 1547 additions and 1515 deletions

282
.idea/csv-editor.xml generated
View File

@@ -1,282 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CsvFileAttributes">
<option name="attributeMap">
<map>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\matplotlib\mpl-data\sample_data\Stocks.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\matplotlib\mpl-data\sample_data\data_x_x2_x3.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\matplotlib\mpl-data\sample_data\msft.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-arccos.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-arccosh.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-arcsin.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-arcsinh.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-arctan.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-arctanh.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-cbrt.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-cos.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-cosh.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-exp.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-exp2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-expm1.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-log.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-log10.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-log1p.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-log2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-sin.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-sinh.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-tan.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\core\tests\data\umath-validation-set-tanh.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\mt19937-testset-1.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\mt19937-testset-2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\pcg64-testset-1.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\pcg64-testset-2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\pcg64dxsm-testset-1.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\pcg64dxsm-testset-2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\philox-testset-1.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\philox-testset-2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\sfc64-testset-1.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\numpy\random\tests\data\sfc64-testset-2.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\sklearn\datasets\data\boston_house_prices.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\sklearn\datasets\data\breast_cancer.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\sklearn\datasets\data\iris.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\sklearn\datasets\data\linnerud_exercise.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\sklearn\datasets\data\linnerud_physiological.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
<entry key="\tools\whisperx\whisperx-env\Lib\site-packages\sklearn\datasets\data\wine_data.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
</map>
</option>
</component>
</project>

View File

@@ -580,98 +580,6 @@
<inspection_tool class="ReplaceAssignmentWithOperatorAssignmentJS" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="ReplaceAssignmentWithOperatorAssignmentJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true"> <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="Tests" level="WARNING" enabled="false" /> <scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
<scope name="Tests" level="WARNING" enabled="false" />
</inspection_tool> </inspection_tool>
<inspection_tool class="ResultSetIndexZero" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="ResultSetIndexZero" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReturnOfInnerClass" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="ReturnOfInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />

124
.idea/uiDesigner.xml generated
View File

@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

295
.idea/workspace.xml generated
View File

@@ -1,37 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="AnalysisUIOptions">
<option name="ANALYZE_INJECTED_CODE" value="false" />
</component>
<component name="AutoImportSettings"> <component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="ff40425e-42c7-4b0e-a76a-6e50cecddb1a" name="Changes" comment=""> <list default="true" id="b9d7e333-acad-414e-8be1-4685e71ee4fe" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/client/src/main/java/com/github/gtache/autosubtitle/client/AbstractClient.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/api/src/main/java/com/github/gtache/autosubtitle/ToolType.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/converter/json/impl/JSONConverterModule.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/impl/JSONSubtitleConverter.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/impl/JSONSubtitleSegment.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/impl/JSONSubtitles.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/modules/subtitle/converter/json/impl/TestJSONConverterModule.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/parameters/fx/FXParametersBinder.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/setup/fx/SetupManagerStringConverter.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/base/Whisper.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/base/WhisperPythonVersion.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisperx/WhisperX.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisperx/WhisperXBundledRoot.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisperx/WhisperXVenvPath.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/TestJSONSubtitleSegment.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/TestJSONSubtitles.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/TestWhisperXJSONSubtitleConverter.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/whisperx-in.json" afterDir="false" />
<change afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/whisperx-out.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/csv-editor.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/uiDesigner.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/client/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/client/RemoteSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/client/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/client/RemoteSubtitleExtractor.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/impl/AbstractSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/impl/AbstractSubtitleExtractor.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/cli/src/main/java/com/github/gtache/autosubtitle/cli/Cli.java" beforeDir="false" afterPath="$PROJECT_DIR$/cli/src/main/java/com/github/gtache/autosubtitle/cli/Cli.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/conda/src/main/java/com/github/gtache/autosubtitle/setup/conda/CondaSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/conda/src/main/java/com/github/gtache/autosubtitle/setup/conda/CondaSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/conda/src/test/java/com/github/gtache/autosubtitle/setup/conda/TestCondaSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/conda/src/test/java/com/github/gtache/autosubtitle/setup/conda/TestCondaSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/core/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/modules/setup/impl/SetupModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/modules/setup/impl/SetupModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/converter/impl/SubtitleConverterModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/converter/impl/SubtitleConverterModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/impl/ASSSubtitleConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/impl/ASSSubtitleConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/main/java/module-info.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/main/java/module-info.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/setup/impl/TestAbstractSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/setup/impl/TestAbstractSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestASSSubtitleConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestASSSubtitleConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/deepl/src/main/java/com/github/gtache/autosubtitle/modules/deepl/DeepLModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/deepl/src/main/java/com/github/gtache/autosubtitle/modules/deepl/DeepLModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/deepl/src/main/java/com/github/gtache/autosubtitle/modules/setup/deepl/DeepLSetupModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/deepl/src/main/java/com/github/gtache/autosubtitle/modules/setup/deepl/DeepLSetupModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/deepl/src/main/java/com/github/gtache/autosubtitle/setup/deepl/DeepLSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/deepl/src/main/java/com/github/gtache/autosubtitle/setup/deepl/DeepLSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/deepl/src/main/java/module-info.java" beforeDir="false" afterPath="$PROJECT_DIR$/deepl/src/main/java/module-info.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/deepl/src/test/java/com/github/gtache/autosubtitle/setup/deepl/TestDeepLSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/deepl/src/test/java/com/github/gtache/autosubtitle/setup/deepl/TestDeepLSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/setup/ffmpeg/FFmpegSetupModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/setup/ffmpeg/FFmpegSetupModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/ParametersBundle_fr.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/ParametersBundle_fr.properties" afterDir="false" /> <change beforePath="$PROJECT_DIR$/ffmpeg/src/test/java/com/github/gtache/autosubtitle/setup/ffmpeg/TestFFmpegSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/ffmpeg/src/test/java/com/github/gtache/autosubtitle/setup/ffmpeg/TestFFmpegSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle.properties" afterDir="false" /> <change beforePath="$PROJECT_DIR$/gui/api/src/main/java/com/github/gtache/autosubtitle/gui/setup/SetupController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/api/src/main/java/com/github/gtache/autosubtitle/gui/setup/SetupController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle_fr.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle_fr.properties" afterDir="false" /> <change beforePath="$PROJECT_DIR$/gui/api/src/main/java/com/github/gtache/autosubtitle/gui/setup/SetupModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/api/src/main/java/com/github/gtache/autosubtitle/gui/setup/SetupModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SetupBundle.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SetupBundle.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SetupBundle_fr.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SetupBundle_fr.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/media/fx/FXMediaController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/media/fx/FXMediaController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/parameters/fx/FXParametersController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/parameters/fx/FXParametersController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/parameters/fx/FXParametersModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/parameters/fx/FXParametersModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/setup/fx/FXSetupController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/setup/fx/FXSetupController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/setup/fx/FXSetupModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/setup/fx/FXSetupModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesBinder.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesBinder.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/work/fx/FXWorkController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/work/fx/FXWorkController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/work/fx/FXWorkModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/work/fx/FXWorkModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/main/resources/com/github/gtache/autosubtitle/gui/fx/setupView.fxml" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/main/resources/com/github/gtache/autosubtitle/gui/fx/setupView.fxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/parameters/fx/TestFXParametersController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/parameters/fx/TestFXParametersController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/parameters/fx/TestFXParametersModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/parameters/fx/TestFXParametersModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/setup/fx/TestFXSetupController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/setup/fx/TestFXSetupController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/setup/fx/TestFXSetupModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/setup/fx/TestFXSetupModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/subtitles/fx/TestFXSubtitlesBinder.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/subtitles/fx/TestFXSubtitlesBinder.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/subtitles/fx/TestFXSubtitlesController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/subtitles/fx/TestFXSubtitlesController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/subtitles/fx/TestFXSubtitlesModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/subtitles/fx/TestFXSubtitlesModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/work/fx/TestFXWorkBinder.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/work/fx/TestFXWorkBinder.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/work/fx/TestFXWorkController.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/work/fx/TestFXWorkController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/work/fx/TestFXWorkModel.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/fx/src/test/java/com/github/gtache/autosubtitle/gui/work/fx/TestFXWorkModel.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/run/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/gui/run/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/run/src/main/java/com/github/gtache/autosubtitle/modules/gui/run/RunComponent.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/run/src/main/java/com/github/gtache/autosubtitle/modules/gui/run/RunComponent.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui/run/src/main/java/module-info.java" beforeDir="false" afterPath="$PROJECT_DIR$/gui/run/src/main/java/module-info.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/base/WhisperSetupModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/base/WhisperSetupModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/extractor/whisper/base/WhisperExtractorModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/extractor/whisper/base/WhisperExtractorModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/parser/json/whisper/base/WhisperJsonModule.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/whisper/base/WhisperModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/whisper/base/WhisperModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/setup/whisper/base/WhisperSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/setup/whisper/base/WhisperSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/whisper/base/WhisperSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/whisper/base/WhisperSubtitleExtractor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisper/base/JSONSubtitleConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisper/base/JSONSubtitleConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisper/base/JSONSubtitleSegment.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisper/base/JSONSubtitleSegment.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisper/base/JSONSubtitles.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisper/base/JSONSubtitles.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/base/src/main/java/module-info.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/module-info.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/PythonVersion.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisperx/WhisperXPythonVersion.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/WhisperBundledRoot.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/base/WhisperBundledRoot.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/WhisperCommonSetupModule.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/WhisperVenvPath.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/base/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisper/base/WhisperVenvPath.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/setup/whisper/AbstractWhisperSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/setup/whisper/AbstractWhisperSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/whisper/AbstractWhisperSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/common/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/whisper/AbstractWhisperSubtitleExtractor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/main/java/module-info.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/common/src/main/java/module-info.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/test/java/com/github/gtache/autosubtitle/modules/setup/whisper/TestWhisperCommonSetupModule.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/test/java/com/github/gtache/autosubtitle/setup/whisper/TestAbstractWhisperSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/common/src/test/java/com/github/gtache/autosubtitle/setup/whisper/TestAbstractWhisperSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/common/src/test/java/com/github/gtache/autosubtitle/subtitle/extractor/whisper/TestAbstractWhisperSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/common/src/test/java/com/github/gtache/autosubtitle/subtitle/extractor/whisper/TestAbstractWhisperSubtitleExtractor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/pom.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisperx/WhisperXSetupModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/setup/whisperx/WhisperXSetupModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/extractor/whisperx/WhisperXExtractorModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/extractor/whisperx/WhisperXExtractorModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/subtitle/parser/json/whisperx/WhisperXJsonModule.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/whisperx/WhisperXModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/modules/whisperx/WhisperXModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/setup/whisperx/WhisperXSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/setup/whisperx/WhisperXSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/whisperx/WhisperXSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/whisperx/WhisperXSubtitleExtractor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/JSONSubtitleConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/WhisperXJSONSubtitleConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/JSONSubtitleSegment.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/JSONSubtitleSegment.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/JSONSubtitleWords.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/JSONSubtitleWords.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/JSONSubtitles.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/JSONSubtitles.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/whisperx/WhisperXExtractionModelProvider.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/com/github/gtache/autosubtitle/whisperx/WhisperXExtractionModelProvider.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/main/java/module-info.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/main/java/module-info.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/modules/setup/whisperx/TestWhisperXSetupModule.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/modules/setup/whisperx/TestWhisperXSetupModule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/modules/subtitle/parser/json/whisperx/TestWhisperXJsonModule.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/setup/whisperx/TestWhisperXSetupManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/setup/whisperx/TestWhisperXSetupManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/extractor/whisperx/TestWhisperXSubtitleExtractor.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/extractor/whisperx/TestWhisperXSubtitleExtractor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/TestJSONSubtitleConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/impl/TestJSONSubtitleConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/TestJSONSubtitleSegment.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/impl/TestJSONSubtitleSegment.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/TestJSONSubtitleWords.java" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/TestJSONSubtitleWords.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/java/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/TestJSONSubtitles.java" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/json/impl/TestJSONSubtitles.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/whisperx-in.json" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/resources/com/github/gtache/autosubtitle/subtitle/converter/json/impl/in.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/whisperx-max-lines.json" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/whisperx-max-lines.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/whisperx-max-words.json" beforeDir="false" afterPath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/converter/json/whisperx/whisperx-max-words.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/whisper/whisperx/src/test/resources/com/github/gtache/autosubtitle/subtitle/parser/json/whisperx/whisperx-out.json" beforeDir="false" afterPath="$PROJECT_DIR$/core/src/test/resources/com/github/gtache/autosubtitle/subtitle/converter/json/impl/out.json" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" /> <option name="LAST_RESOLUTION" value="IGNORE" />
</component> </component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Record" />
<option value="Interface" />
<option value="Class" />
</list>
</option>
</component>
<component name="FormatOnSaveOptions"> <component name="FormatOnSaveOptions">
<option name="myRunOnSave" value="true" /> <option name="myRunOnSave" value="true" />
</component> </component>
@@ -51,9 +148,7 @@
<option name="generalSettings"> <option name="generalSettings">
<MavenGeneralSettings> <MavenGeneralSettings>
<option name="alwaysUpdateSnapshots" value="true" /> <option name="alwaysUpdateSnapshots" value="true" />
<option name="customMavenHome" value="F:\Maven" />
<option name="localRepository" value="D:\caches\.m2\" /> <option name="localRepository" value="D:\caches\.m2\" />
<option name="mavenHomeTypeForPersistence" value="CUSTOM" />
</MavenGeneralSettings> </MavenGeneralSettings>
</option> </option>
<option name="importingSettings"> <option name="importingSettings">
@@ -67,69 +162,44 @@
<component name="OptimizeOnSaveOptions"> <component name="OptimizeOnSaveOptions">
<option name="myRunOnSave" value="true" /> <option name="myRunOnSave" value="true" />
</component> </component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="QODANA_PROBLEMS_VIEW_TAB" />
</component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
&quot;customColor&quot;: &quot;&quot;, &quot;customColor&quot;: &quot;&quot;,
&quot;associatedIndex&quot;: 4 &quot;associatedIndex&quot;: 4
}</component> }</component>
<component name="ProjectId" id="2mOTkDSFeKNrF2FBh5zobHeX11u" /> <component name="ProjectId" id="2mwO59xISTvRVmoGPPwWN1oEXCt" />
<component name="ProjectViewState"> <component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;Application.Main.executor&quot;: &quot;Run&quot;, "Application.Main.executor": "Run",
&quot;JUnit.TestASSSubtitleConverter.executor&quot;: &quot;Run&quot;, "Maven.autosubtitle [clean,package,-DskipTests].executor": "Run",
&quot;JUnit.TestAbstractSetupManager.executor&quot;: &quot;Run&quot;, "Maven.autosubtitle [clean,package].executor": "Run",
&quot;JUnit.TestFFmpegVideoConverter.executor&quot;: &quot;Run&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;JUnit.TestFXSubtitlesBinder.executor&quot;: &quot;Run&quot;, "com.codeium.enabled": "true",
&quot;Maven.autosubtitle [clean,package,-DskipTests].executor&quot;: &quot;Run&quot;, "git-widget-placeholder": "master",
&quot;Maven.autosubtitle [clean,package].executor&quot;: &quot;Run&quot;, "ignore.virus.scanning.warn.message": "true",
&quot;Maven.autosubtitle [clean].executor&quot;: &quot;Run&quot;, "kotlin-language-version-configured": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "node.js.detected.package.eslint": "true",
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;, "node.js.detected.package.tslint": "true",
&quot;com.codeium.enabled&quot;: &quot;true&quot;, "node.js.selected.package.eslint": "(autodetect)",
&quot;git-widget-placeholder&quot;: &quot;master&quot;, "node.js.selected.package.tslint": "(autodetect)",
&quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;, "nodejs_package_manager_path": "npm",
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;, "project.structure.last.edited": "Modules",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "project.structure.proportion": "0.0",
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, "project.structure.side.proportion": "0.0",
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, "settings.editor.selected.configurable": "reference.projectsettings.compiler.annotationProcessors",
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, "vue.rearranger.settings.migration": "true"
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
&quot;run.code.analysis.last.selected.profile&quot;: &quot;aDefault&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;actions.on.save&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}</component> }]]></component>
<component name="QodanaReportsService">
<option name="descriptions">
<ReportDescription localRun="true" path="C:\Temp\UserTemp\qodana_output\qodana.sarif.json" reportGuid="6c32d48e-3af1-4a39-9921-31ac1f556472" reportId="auto-subtitle/qodana/2024-09-22" />
</option>
</component>
<component name="RecentsManager">
<key name="CopyClassDialog.RECENTS_KEY">
<recent name="com.github.gtache.autosubtitle.subtitle.impl" />
<recent name="com.github.gtache.autosubtitle.subtitle.extractor.impl" />
<recent name="com.github.gtache.autosubtitle.subtitle.converter.impl" />
<recent name="com.github.gtache.autosubtitle.subtitle" />
<recent name="com.github.gtache.autosubtitle.subtitle.converter" />
</key>
</component>
<component name="RunAnythingCache"> <component name="RunAnythingCache">
<option name="myCommands"> <option name="myCommands">
<command value="mvn clean" />
<command value="mvn clean package -DskipTests" />
<command value="mvn clean package" /> <command value="mvn clean package" />
<command value="mvn clean package -DskipTests" />
</option> </option>
</component> </component>
<component name="RunManager" selected="Application.Main"> <component name="RunManager">
<configuration default="true" type="Applet"> <configuration default="true" type="Applet">
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" /> <option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
<method v="2"> <method v="2">
@@ -165,70 +235,6 @@
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
</configuration> </configuration>
<configuration name="TestASSSubtitleConverter" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="autosubtitle-core" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.github.gtache.autosubtitle.subtitle.converter.impl.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="com.github.gtache.autosubtitle.subtitle.converter.impl" />
<option name="MAIN_CLASS_NAME" value="com.github.gtache.autosubtitle.subtitle.converter.impl.TestASSSubtitleConverter" />
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="TestAbstractSetupManager" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="autosubtitle-core" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.github.gtache.autosubtitle.setup.impl.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="com.github.gtache.autosubtitle.setup.impl" />
<option name="MAIN_CLASS_NAME" value="com.github.gtache.autosubtitle.setup.impl.TestAbstractSetupManager" />
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="TestFFmpegVideoConverter" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="autosubtitle-ffmpeg" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.github.gtache.autosubtitle.ffmpeg.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="com.github.gtache.autosubtitle.ffmpeg" />
<option name="MAIN_CLASS_NAME" value="com.github.gtache.autosubtitle.ffmpeg.TestFFmpegVideoConverter" />
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="TestFXSubtitlesBinder" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="autosubtitle-gui-fx" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.github.gtache.autosubtitle.gui.subtitles.fx.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="com.github.gtache.autosubtitle.gui.subtitles.fx" />
<option name="MAIN_CLASS_NAME" value="com.github.gtache.autosubtitle.gui.subtitles.fx.TestFXSubtitlesBinder" />
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="JUnit" factoryName="JUnit"> <configuration default="true" type="JUnit" factoryName="JUnit">
<option name="TEST_OBJECT" value="class" /> <option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" /> <option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
@@ -311,34 +317,27 @@
<recent_temporary> <recent_temporary>
<list> <list>
<item itemvalue="Application.Main" /> <item itemvalue="Application.Main" />
<item itemvalue="JUnit.TestFXSubtitlesBinder" />
<item itemvalue="JUnit.TestFFmpegVideoConverter" />
<item itemvalue="JUnit.TestAbstractSetupManager" />
<item itemvalue="JUnit.TestASSSubtitleConverter" />
</list> </list>
</recent_temporary> </recent_temporary>
</component> </component>
<component name="SharedIndexes"> <component name="SharedIndexes">
<attachedChunks> <attachedChunks>
<set> <set>
<option value="bundled-jdk-9823dce3aa75-28b599e66164-intellij.indexing.shared.core-IU-242.22855.74" /> <option value="bundled-jdk-9823dce3aa75-28b599e66164-intellij.indexing.shared.core-IU-242.23339.11" />
<option value="bundled-js-predefined-d6986cc7102b-5c90d61e3bab-JavaScript-IU-242.22855.74" /> <option value="bundled-js-predefined-d6986cc7102b-5c90d61e3bab-JavaScript-IU-242.23339.11" />
</set> </set>
</attachedChunks> </attachedChunks>
</component> </component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager"> <component name="TaskManager">
<task active="true" id="Default" summary="Default task"> <task active="true" id="Default" summary="Default task">
<changelist id="ff40425e-42c7-4b0e-a76a-6e50cecddb1a" name="Changes" comment="" /> <changelist id="b9d7e333-acad-414e-8be1-4685e71ee4fe" name="Changes" comment="" />
<created>1726946764733</created> <created>1727983986841</created>
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1726946764733</updated> <updated>1727983986841</updated>
<workItem from="1726946765439" duration="148000" /> <workItem from="1727983987865" duration="45000" />
<workItem from="1727010656600" duration="16805000" /> <workItem from="1727984039387" duration="1228000" />
<workItem from="1727202729910" duration="57000" />
<workItem from="1727202805574" duration="1096000" />
<workItem from="1727206350052" duration="1842000" />
</task> </task>
<servers /> <servers />
</component> </component>

View File

@@ -0,0 +1,19 @@
package com.github.gtache.autosubtitle;
/**
* Type of a tool
*/
public enum ToolType {
/**
* The video converter (used to add subtitles)
*/
VIDEO_CONVERTER,
/**
* The subtitle extractor (used to extract subtitles from a video)
*/
SUBTITLE_EXTRACTOR,
/**
* The subtitle translator (used to translate subtitles from one language to another)
*/
TRANSLATOR
}

View File

@@ -1,5 +1,7 @@
package com.github.gtache.autosubtitle.setup; package com.github.gtache.autosubtitle.setup;
import com.github.gtache.autosubtitle.ToolType;
/** /**
* Manages the setup of a component * Manages the setup of a component
*/ */
@@ -10,6 +12,11 @@ public interface SetupManager {
*/ */
String name(); String name();
/**
* @return the type of the component
*/
ToolType type();
/** /**
* @return the status of the component setup * @return the status of the component setup
*/ */

View File

@@ -6,12 +6,15 @@ import picocli.CommandLine;
import java.util.Set; import java.util.Set;
/**
* Main class for CLI
*/
@CommandLine.Command(name = "autosubtitle", mixinStandardHelpOptions = true, version = "autosubtitle 1.0-SNAPSHOT", description = "CLI for auto-subtitle") @CommandLine.Command(name = "autosubtitle", mixinStandardHelpOptions = true, version = "autosubtitle 1.0-SNAPSHOT", description = "CLI for auto-subtitle")
public final class Cli implements Runnable { public final class Cli implements Runnable {
@CommandLine.Option(names = {"-b", "--burn"}, description = "Burn the subtitles. Otherwise, adds them to the video", defaultValue = "false") @CommandLine.Option(names = {"-b", "--burn"}, description = "Burns the subtitles. Otherwise, adds them to the video", defaultValue = "false")
private boolean burn; private boolean burn;
@CommandLine.Option(names = {"-e", "--extractor"}, description = "The subtitle extractor to use [whisper]", defaultValue = "whisper") @CommandLine.Option(names = {"-e", "--extractor"}, description = "The subtitle extractor to use [whisperx]", defaultValue = "whisperx")
private String extractor; private String extractor;
@CommandLine.Option(names = {"-i", "--input"}, description = "The input file", required = true) @CommandLine.Option(names = {"-i", "--input"}, description = "The input file", required = true)
private String input; private String input;

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.conda; package com.github.gtache.autosubtitle.setup.conda;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.impl.OS; import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
@@ -42,6 +43,11 @@ public class CondaSetupManager extends AbstractSetupManager {
return "conda"; return "conda";
} }
@Override
public ToolType type() {
return null; //Just an intermediary tool
}
@Override @Override
protected SetupStatus getStatus() throws SetupException { protected SetupStatus getStatus() throws SetupException {
if (isSystemCondaInstalled()) { if (isSystemCondaInstalled()) {

View File

@@ -68,6 +68,11 @@ class TestCondaSetupManager {
assertEquals("conda", condaSetupManager.name()); assertEquals("conda", condaSetupManager.name());
} }
@Test
void testType() {
assertNull(condaSetupManager.type());
}
@Test @Test
void testGetStatusIsSystemInstalled() throws SetupException { void testGetStatusIsSystemInstalled() throws SetupException {
assertEquals(SetupStatus.SYSTEM_INSTALLED, condaSetupManager.getStatus()); assertEquals(SetupStatus.SYSTEM_INSTALLED, condaSetupManager.getStatus());

View File

@@ -24,6 +24,10 @@
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId> <artifactId>log4j-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-core</artifactId>

View File

@@ -1,11 +1,14 @@
package com.github.gtache.autosubtitle.modules.setup.impl; package com.github.gtache.autosubtitle.modules.setup.impl;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.setup.SetupManager;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Map;
/** /**
* Dagger core module for setup * Dagger core module for setup
@@ -32,4 +35,22 @@ public final class SetupModule {
static HttpClient providesHttpClient() { static HttpClient providesHttpClient() {
return HttpClient.newHttpClient(); return HttpClient.newHttpClient();
} }
@Provides
static Map<ToolType, Map<String, SetupManager>> providesSetupManagers(@VideoConverterSetup final Map<String, SetupManager> convertersManagers,
@SubtitleExtractorSetup final Map<String, SetupManager> extractorsManagers,
@TranslatorSetup final Map<String, SetupManager> translatorsManagers) {
return Map.of(ToolType.VIDEO_CONVERTER, convertersManagers,
ToolType.SUBTITLE_EXTRACTOR, extractorsManagers,
ToolType.TRANSLATOR, translatorsManagers);
}
@Provides
static Map<ToolType, SetupManager> providesDefaultManagers(@VideoConverterSetup final SetupManager videoConverterManager,
@SubtitleExtractorSetup final SetupManager subtitleExtractorManager,
@TranslatorSetup final SetupManager translatorManager) {
return Map.of(ToolType.VIDEO_CONVERTER, videoConverterManager,
ToolType.SUBTITLE_EXTRACTOR, subtitleExtractorManager,
ToolType.TRANSLATOR, translatorManager);
}
} }

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.modules.subtitle.converter.impl; package com.github.gtache.autosubtitle.modules.subtitle.converter.impl;
import com.github.gtache.autosubtitle.modules.subtitle.converter.json.impl.JSONConverterModule;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter; import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider; import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ASSSubtitleConverter; import com.github.gtache.autosubtitle.subtitle.converter.impl.ASSSubtitleConverter;
@@ -13,7 +14,7 @@ import dagger.multibindings.StringKey;
/** /**
* Dagger module for the subtitle converters * Dagger module for the subtitle converters
*/ */
@Module @Module(includes = JSONConverterModule.class)
public abstract class SubtitleConverterModule { public abstract class SubtitleConverterModule {
private SubtitleConverterModule() { private SubtitleConverterModule() {

View File

@@ -1,8 +1,8 @@
package com.github.gtache.autosubtitle.modules.subtitle.parser.json.whisperx; package com.github.gtache.autosubtitle.modules.subtitle.converter.json.impl;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter; import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.parser.json.whisperx.JSONSubtitleConverter; import com.github.gtache.autosubtitle.subtitle.converter.json.impl.JSONSubtitleConverter;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
@@ -11,17 +11,19 @@ import dagger.multibindings.StringKey;
import javax.inject.Singleton; import javax.inject.Singleton;
/**
* Dagger module for the json subtitle converter
*/
@Module @Module
public abstract class WhisperXJsonModule { public abstract class JSONConverterModule {
private WhisperXJsonModule() {
private JSONConverterModule() {
} }
@Binds @Binds
@IntoMap @IntoMap
@StringKey("json") @StringKey("json")
abstract SubtitleConverter bindsJSONSubtitleConverter(final JSONSubtitleConverter subtitleConverter); abstract SubtitleConverter bindsJsonSubtitleConverter(final JSONSubtitleConverter converter);
@Provides @Provides
@Singleton @Singleton

View File

@@ -23,8 +23,6 @@ import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
/** /**
* Converts subtitles to SRT format * Converts subtitles to SRT format
*/ */
@@ -36,11 +34,11 @@ public class ASSSubtitleConverter implements SubtitleConverter<SubtitleImpl> {
private static final String EVENTS_SECTION = "[Events]"; private static final String EVENTS_SECTION = "[Events]";
private static final String STYLES_SECTION = "[V4+ Styles]"; private static final String STYLES_SECTION = "[V4+ Styles]";
private static final Pattern NEWLINE_PATTERN = Pattern.compile("\\n"); private static final Pattern NEWLINE_PATTERN = Pattern.compile("\\n");
private final Translator<?> translator; private final Map<String, Translator<?>> translators;
@Inject @Inject
ASSSubtitleConverter(final Translator translator) { ASSSubtitleConverter(final Map<String, Translator<?>> translators) {
this.translator = requireNonNull(translator); this.translators = Map.copyOf(translators);
} }
@Override @Override
@@ -99,7 +97,7 @@ public class ASSSubtitleConverter implements SubtitleConverter<SubtitleImpl> {
final var fonts = parseFonts(content, options.defaultFont()); final var fonts = parseFonts(content, options.defaultFont());
final var subtitles = parseSubtitles(content, fonts); final var subtitles = parseSubtitles(content, fonts);
final var text = subtitles.stream().map(Subtitle::content).collect(Collectors.joining()); final var text = subtitles.stream().map(Subtitle::content).collect(Collectors.joining());
final var language = translator.getLanguage(text); final var language = translators.values().iterator().next().getLanguage(text); //Use any translator for now
return new SubtitleCollectionImpl<>(text, subtitles, language); return new SubtitleCollectionImpl<>(text, subtitles, language);
} }

View File

@@ -0,0 +1,74 @@
package com.github.gtache.autosubtitle.subtitle.converter.json.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.converter.FormatException;
import com.github.gtache.autosubtitle.subtitle.converter.FormatOptions;
import com.github.gtache.autosubtitle.subtitle.converter.ParseException;
import com.github.gtache.autosubtitle.subtitle.converter.ParseOptions;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.impl.SubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.impl.SubtitleImpl;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* {@link SubtitleConverter} implementation for JSON files
*/
@Singleton
public class JSONSubtitleConverter implements SubtitleConverter<SubtitleImpl> {
private final ObjectMapper mapper;
@Inject
JSONSubtitleConverter(final ObjectMapper mapper) {
this.mapper = Objects.requireNonNull(mapper);
}
@Override
public String format(final SubtitleCollection<?> collection, final FormatOptions options) throws FormatException {
final var segments = collection.subtitles().stream().map(s -> new JSONSubtitleSegment(s.start(),
s.end(), s.content())).toList();
final var subtitles = new JSONSubtitles(segments, collection.language());
try {
return mapper.writeValueAsString(subtitles);
} catch (final JsonProcessingException e) {
throw new FormatException(e);
}
}
@Override
public SubtitleCollectionImpl<SubtitleImpl> parse(final String content, final ParseOptions options) throws ParseException {
try {
final var json = mapper.readValue(content, JSONSubtitles.class);
final var subtitles = json.segments().stream().flatMap(s -> {
final var start = s.start();
final var end = s.end();
return Stream.of(new SubtitleImpl(s.text(), start, end, null, null));
}).sorted(Comparator.comparing(Subtitle::start).thenComparing(Subtitle::end)).toList();
final var language = json.language();
final var subtitlesText = subtitles.stream().map(s -> s.content().trim()).collect(Collectors.joining(" "));
return new SubtitleCollectionImpl<>(subtitlesText, subtitles, language);
} catch (final Exception e) {
throw new ParseException(e);
}
}
@Override
public boolean canParse(final Path file) {
return file.getFileName().toString().endsWith(".json");
}
@Override
public String formatName() {
return "json";
}
}

View File

@@ -0,0 +1,26 @@
package com.github.gtache.autosubtitle.subtitle.converter.json.impl;
import static java.util.Objects.requireNonNull;
/**
* A subtitle segment as a JSON
*
* @param start The start in milliseconds
* @param end The end in milliseconds
* @param text The text
*/
public record JSONSubtitleSegment(long start, long end, String text) {
public JSONSubtitleSegment {
if (start < 0) {
throw new IllegalArgumentException("start must be >= 0 : " + start);
}
if (end < 0) {
throw new IllegalArgumentException("end must be >= 0 : " + end);
}
if (start > end) {
throw new IllegalArgumentException("start must be <= end : " + start + " > " + end);
}
requireNonNull(text);
}
}

View File

@@ -0,0 +1,21 @@
package com.github.gtache.autosubtitle.subtitle.converter.json.impl;
import com.github.gtache.autosubtitle.Language;
import java.util.List;
import static java.util.Objects.requireNonNull;
/**
* Root json object for subtitles
*
* @param segments The list of subtitle segments
* @param language The subtitles language
*/
public record JSONSubtitles(List<JSONSubtitleSegment> segments, Language language) {
public JSONSubtitles {
segments = List.copyOf(segments);
requireNonNull(language);
}
}

View File

@@ -6,18 +6,22 @@ module com.github.gtache.autosubtitle.core {
requires transitive dagger; requires transitive dagger;
requires transitive java.net.http; requires transitive java.net.http;
requires transitive javax.inject; requires transitive javax.inject;
requires transitive java.prefs;
requires transitive com.fasterxml.jackson.databind;
requires org.apache.logging.log4j; requires org.apache.logging.log4j;
requires java.prefs;
exports com.github.gtache.autosubtitle.impl; exports com.github.gtache.autosubtitle.impl;
exports com.github.gtache.autosubtitle.archive.impl; exports com.github.gtache.autosubtitle.archive.impl;
exports com.github.gtache.autosubtitle.process.impl; exports com.github.gtache.autosubtitle.process.impl;
exports com.github.gtache.autosubtitle.setup.impl; exports com.github.gtache.autosubtitle.setup.impl;
exports com.github.gtache.autosubtitle.subtitle.impl; exports com.github.gtache.autosubtitle.subtitle.impl;
exports com.github.gtache.autosubtitle.subtitle.converter.impl;
exports com.github.gtache.autosubtitle.subtitle.converter.json.impl;
exports com.github.gtache.autosubtitle.subtitle.extractor.impl;
exports com.github.gtache.autosubtitle.modules.impl; exports com.github.gtache.autosubtitle.modules.impl;
exports com.github.gtache.autosubtitle.modules.setup.impl; exports com.github.gtache.autosubtitle.modules.setup.impl;
exports com.github.gtache.autosubtitle.subtitle.extractor.impl;
exports com.github.gtache.autosubtitle.subtitle.converter.impl;
exports com.github.gtache.autosubtitle.modules.subtitle.impl; exports com.github.gtache.autosubtitle.modules.subtitle.impl;
exports com.github.gtache.autosubtitle.modules.subtitle.converter.impl;
exports com.github.gtache.autosubtitle.modules.subtitle.converter.json.impl;
} }

View File

@@ -0,0 +1,14 @@
package com.github.gtache.autosubtitle.modules.subtitle.converter.json.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
class TestJSONConverterModule {
@Test
void testProvidesObjectMapper() {
assertInstanceOf(ObjectMapper.class, JSONConverterModule.providesObjectMapper());
}
}

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.impl; package com.github.gtache.autosubtitle.setup.impl;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupAction; import com.github.gtache.autosubtitle.setup.SetupAction;
import com.github.gtache.autosubtitle.setup.SetupEvent; import com.github.gtache.autosubtitle.setup.SetupEvent;
@@ -244,6 +245,11 @@ class TestAbstractSetupManager {
return "dummy"; return "dummy";
} }
@Override
public ToolType type() {
return ToolType.VIDEO_CONVERTER;
}
@Override @Override
public void install() { public void install() {
} }

View File

@@ -17,6 +17,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -44,7 +45,7 @@ class TestASSSubtitleConverter {
this.formatOptions = requireNonNull(formatOptions); this.formatOptions = requireNonNull(formatOptions);
this.parseOptions = requireNonNull(parseOptions); this.parseOptions = requireNonNull(parseOptions);
this.videoInfo = requireNonNull(videoInfo); this.videoInfo = requireNonNull(videoInfo);
this.converter = new ASSSubtitleConverter(translator); this.converter = new ASSSubtitleConverter(Map.of("first", translator));
} }
@BeforeEach @BeforeEach

View File

@@ -0,0 +1,81 @@
package com.github.gtache.autosubtitle.subtitle.converter.json.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.converter.FormatException;
import com.github.gtache.autosubtitle.subtitle.converter.FormatOptions;
import com.github.gtache.autosubtitle.subtitle.converter.ParseException;
import com.github.gtache.autosubtitle.subtitle.converter.ParseOptions;
import com.github.gtache.autosubtitle.subtitle.impl.SubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.impl.SubtitleImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestJSONSubtitleConverter {
private final ParseOptions parseOptions;
private final FormatOptions formatOptions;
private final JSONSubtitleConverter converter;
TestJSONSubtitleConverter(@Mock final ParseOptions parseOptions, @Mock final FormatOptions formatOptions) {
this.parseOptions = Objects.requireNonNull(parseOptions);
this.formatOptions = Objects.requireNonNull(formatOptions);
this.converter = new JSONSubtitleConverter(new ObjectMapper());
}
@BeforeEach
void beforeEach() {
when(parseOptions.maxLineLength()).thenReturn(100);
when(parseOptions.maxLines()).thenReturn(2);
}
@Test
void testFormatName() {
assertEquals("json", converter.formatName());
}
@Test
void testParseFormat() throws IOException, ParseException, FormatException {
try (final var inStream = getClass().getResourceAsStream("in.json");
final var outStream = getClass().getResourceAsStream("out.json")) {
if (inStream == null || outStream == null) {
throw new IOException("File not found");
}
final var in = new String(inStream.readAllBytes(), StandardCharsets.UTF_8);
final var out = new String(outStream.readAllBytes(), StandardCharsets.UTF_8);
final var expected = new SubtitleCollectionImpl<Subtitle>("This is a test. Yes.", List.of(new SubtitleImpl("This is a test.", 9, 410, null, null), new SubtitleImpl("Yes.", 450, 6963, null, null)), Language.FR);
assertEquals(expected, converter.parse(in, parseOptions));
assertEquals(out, converter.format(expected, formatOptions));
}
}
@ParameterizedTest
@CsvSource({
"test.json,true",
".json,true",
"abcd.json,true",
"abcd.json2,false",
"abcd.js,false",
"abcd.jso,false",
"json,false",
})
void testCanParse(final String name, final boolean expected) {
assertEquals(expected, converter.canParse(Path.of(name)));
}
}

View File

@@ -0,0 +1,36 @@
package com.github.gtache.autosubtitle.subtitle.converter.json.impl;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class TestJSONSubtitleSegment {
private final long start;
private final long end;
private final String text;
private final JSONSubtitleSegment segment;
TestJSONSubtitleSegment() {
this.start = 2;
this.end = 4;
this.text = "test";
this.segment = new JSONSubtitleSegment(start, end, text);
}
@Test
void testGetters() {
assertEquals(start, segment.start());
assertEquals(end, segment.end());
assertEquals(text, segment.text());
}
@Test
void testIllegal() {
assertThrows(NullPointerException.class, () -> new JSONSubtitleSegment(start, end, null));
assertThrows(IllegalArgumentException.class, () -> new JSONSubtitleSegment(-1, end, text));
assertThrows(IllegalArgumentException.class, () -> new JSONSubtitleSegment(start, -1, text));
assertThrows(IllegalArgumentException.class, () -> new JSONSubtitleSegment(end, start, text));
}
}

View File

@@ -0,0 +1,39 @@
package com.github.gtache.autosubtitle.subtitle.converter.json.impl;
import com.github.gtache.autosubtitle.Language;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ExtendWith(MockitoExtension.class)
class TestJSONSubtitles {
private final List<JSONSubtitleSegment> segments;
private final Language language;
private final JSONSubtitles subtitles;
TestJSONSubtitles(@Mock final JSONSubtitleSegment segment, @Mock final Language language) {
this.segments = List.of(segment);
this.language = Objects.requireNonNull(language);
this.subtitles = new JSONSubtitles(segments, language);
}
@Test
void testGetters() {
assertEquals(segments, subtitles.segments());
assertEquals(language, subtitles.language());
}
@Test
void testIllegal() {
assertThrows(NullPointerException.class, () -> new JSONSubtitles(null, language));
assertThrows(NullPointerException.class, () -> new JSONSubtitles(segments, null));
}
}

View File

@@ -0,0 +1,15 @@
{
"segments": [
{
"start": 9,
"end": 410,
"text": "This is a test."
},
{
"start": 450,
"end": 6963,
"text": "Yes."
}
],
"language": "FR"
}

View File

@@ -0,0 +1 @@
{"segments":[{"start":9,"end":410,"text":"This is a test."},{"start":450,"end":6963,"text":"Yes."}],"language":"FR"}

View File

@@ -6,6 +6,8 @@ import com.github.gtache.autosubtitle.translation.deepl.DeepLTranslator;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import org.apache.tika.language.detect.LanguageDetector; import org.apache.tika.language.detect.LanguageDetector;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -18,6 +20,11 @@ import java.io.UncheckedIOException;
@Module(includes = DeepLSetupModule.class) @Module(includes = DeepLSetupModule.class)
public abstract class DeepLModule { public abstract class DeepLModule {
@Binds
@IntoMap
@StringKey("deepl")
abstract Translator<?> bindsTranslatorInMap(final DeepLTranslator translator);
@Binds @Binds
abstract Translator bindsTranslator(final DeepLTranslator translator); abstract Translator bindsTranslator(final DeepLTranslator translator);

View File

@@ -5,6 +5,8 @@ import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.deepl.DeepLSetupManager; import com.github.gtache.autosubtitle.setup.deepl.DeepLSetupManager;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/** /**
* Dagger module for DeepL setup * Dagger module for DeepL setup
@@ -16,6 +18,12 @@ public abstract class DeepLSetupModule {
@Binds @Binds
@TranslatorSetup @TranslatorSetup
@IntoMap
@StringKey("deepl")
abstract SetupManager bindsSetupManager(final DeepLSetupManager setupManager); abstract SetupManager bindsSetupManager(final DeepLSetupManager setupManager);
@Binds
@TranslatorSetup
abstract SetupManager bindsDefaultSetupManager(final DeepLSetupManager setupManager);
} }

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.deepl; package com.github.gtache.autosubtitle.setup.deepl;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupManager; import com.github.gtache.autosubtitle.setup.SetupManager;
@@ -8,6 +9,7 @@ import com.github.gtache.autosubtitle.setup.SetupUserBridge;
import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager; import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.util.Objects; import java.util.Objects;
import java.util.prefs.BackingStoreException; import java.util.prefs.BackingStoreException;
@@ -16,6 +18,7 @@ import java.util.prefs.Preferences;
/** /**
* {@link SetupManager} for DeepL * {@link SetupManager} for DeepL
*/ */
@Singleton
public class DeepLSetupManager extends AbstractSetupManager { public class DeepLSetupManager extends AbstractSetupManager {
private static final String DEEPL_API_KEY = "deepl.api.key"; private static final String DEEPL_API_KEY = "deepl.api.key";
@@ -42,6 +45,11 @@ public class DeepLSetupManager extends AbstractSetupManager {
return "DeepL"; return "DeepL";
} }
@Override
public ToolType type() {
return ToolType.TRANSLATOR;
}
@Override @Override
public void install() throws SetupException { public void install() throws SetupException {
final var key = userBridge.askForUserInput("Please enter your DeepL API key - https://www.deepl.com/pro-api? (It will be stored unencrypted)"); final var key = userBridge.askForUserInput("Please enter your DeepL API key - https://www.deepl.com/pro-api? (It will be stored unencrypted)");

View File

@@ -7,7 +7,10 @@ module com.github.gtache.autosubtitle.deepl {
requires transitive java.prefs; requires transitive java.prefs;
requires transitive org.apache.tika.core; requires transitive org.apache.tika.core;
requires transitive language.detector; requires transitive language.detector;
exports com.github.gtache.autosubtitle.modules.deepl;
exports com.github.gtache.autosubtitle.translation.deepl;
exports com.github.gtache.autosubtitle.setup.deepl; exports com.github.gtache.autosubtitle.setup.deepl;
exports com.github.gtache.autosubtitle.translation.deepl;
exports com.github.gtache.autosubtitle.modules.deepl;
exports com.github.gtache.autosubtitle.modules.setup.deepl;
} }

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.deepl; package com.github.gtache.autosubtitle.setup.deepl;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupStatus; import com.github.gtache.autosubtitle.setup.SetupStatus;
@@ -44,6 +45,11 @@ class TestDeepLSetupManager {
assertEquals(SetupStatus.BUNDLE_INSTALLED, setupManager.getStatus()); assertEquals(SetupStatus.BUNDLE_INSTALLED, setupManager.getStatus());
} }
@Test
void testType() {
assertEquals(ToolType.TRANSLATOR, setupManager.type());
}
@Test @Test
void testInstall() throws BackingStoreException, SetupException { void testInstall() throws BackingStoreException, SetupException {
final var key = "key"; final var key = "key";

View File

@@ -7,6 +7,8 @@ import com.github.gtache.autosubtitle.ffmpeg.FFprobeVideoLoader;
import com.github.gtache.autosubtitle.modules.setup.ffmpeg.FFmpegSetupModule; import com.github.gtache.autosubtitle.modules.setup.ffmpeg.FFmpegSetupModule;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/** /**
* Dagger module for FFmpeg * Dagger module for FFmpeg
@@ -19,8 +21,18 @@ public abstract class FFmpegModule {
} }
@Binds @Binds
@IntoMap
@StringKey("ffmpeg")
abstract VideoConverter bindsVideoConverter(final FFmpegVideoConverter converter); abstract VideoConverter bindsVideoConverter(final FFmpegVideoConverter converter);
@Binds @Binds
abstract VideoConverter bindsDefaultVideoConverter(final FFmpegVideoConverter converter);
@Binds
@IntoMap
@StringKey("ffprobe")
abstract VideoLoader bindsVideoLoader(final FFprobeVideoLoader loader); abstract VideoLoader bindsVideoLoader(final FFprobeVideoLoader loader);
@Binds
abstract VideoLoader bindsDefaultVideoLoader(final FFprobeVideoLoader loader);
} }

View File

@@ -36,19 +36,25 @@ public abstract class FFmpegSetupModule {
@Binds @Binds
@StringKey("tar")
@IntoMap @IntoMap
@StringKey("tar")
abstract Archiver bindsTarDecompresser(final TarArchiver decompresser); abstract Archiver bindsTarDecompresser(final TarArchiver decompresser);
@Binds @Binds
@StringKey("xz")
@IntoMap @IntoMap
@StringKey("xz")
abstract Archiver bindsXZDecompresser(final XZArchiver decompresser); abstract Archiver bindsXZDecompresser(final XZArchiver decompresser);
@Binds @Binds
@VideoConverterSetup @VideoConverterSetup
@IntoMap
@StringKey("ffmpeg")
abstract SetupManager bindsFFmpegSetupManager(final FFmpegSetupManager manager); abstract SetupManager bindsFFmpegSetupManager(final FFmpegSetupManager manager);
@Binds
@VideoConverterSetup
abstract SetupManager bindsDefaultSetupManager(final FFmpegSetupManager manager);
@Provides @Provides
static FFmpegSetupConfiguration providesFFmpegSetupConfiguration(@FFBundledRoot final Path root, @FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath, static FFmpegSetupConfiguration providesFFmpegSetupConfiguration(@FFBundledRoot final Path root, @FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath,
@FFmpegInstallerPath final Path ffmpegInstallerPath, @FFProbeInstallerPath final Path ffprobeInstallerPath, @FFmpegInstallerPath final Path ffmpegInstallerPath, @FFProbeInstallerPath final Path ffprobeInstallerPath,

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.ffmpeg; package com.github.gtache.autosubtitle.setup.ffmpeg;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.archive.ArchiverProvider; import com.github.gtache.autosubtitle.archive.ArchiverProvider;
import com.github.gtache.autosubtitle.impl.Architecture; import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
@@ -9,6 +10,7 @@ import com.github.gtache.autosubtitle.setup.SetupStatus;
import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager; import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException; import java.io.IOException;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.nio.file.Files; import java.nio.file.Files;
@@ -24,6 +26,7 @@ import static java.util.Objects.requireNonNull;
* {@link SetupManager} managing the FFmpeg installation * {@link SetupManager} managing the FFmpeg installation
*/ */
//TODO add gpg/signature check //TODO add gpg/signature check
@Singleton
public class FFmpegSetupManager extends AbstractSetupManager { public class FFmpegSetupManager extends AbstractSetupManager {
private final FFmpegSetupConfiguration configuration; private final FFmpegSetupConfiguration configuration;
private final ArchiverProvider archiverProvider; private final ArchiverProvider archiverProvider;
@@ -41,6 +44,11 @@ public class FFmpegSetupManager extends AbstractSetupManager {
return "FFmpeg"; return "FFmpeg";
} }
@Override
public ToolType type() {
return ToolType.VIDEO_CONVERTER;
}
@Override @Override
public SetupStatus getStatus() throws SetupException { public SetupStatus getStatus() throws SetupException {
try { try {

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.ffmpeg; package com.github.gtache.autosubtitle.setup.ffmpeg;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.archive.Archiver; import com.github.gtache.autosubtitle.archive.Archiver;
import com.github.gtache.autosubtitle.archive.ArchiverProvider; import com.github.gtache.autosubtitle.archive.ArchiverProvider;
import com.github.gtache.autosubtitle.impl.Architecture; import com.github.gtache.autosubtitle.impl.Architecture;
@@ -84,6 +85,11 @@ class TestFFmpegSetupManager {
assertEquals("FFmpeg", setupManager.name()); assertEquals("FFmpeg", setupManager.name());
} }
@Test
void testType() {
assertEquals(ToolType.VIDEO_CONVERTER, setupManager.type());
}
@Test @Test
void testGetStatusSystemFalse() throws IOException, SetupException { void testGetStatusSystemFalse() throws IOException, SetupException {
final var ffmpegPath = Paths.get("path"); final var ffmpegPath = Paths.get("path");

View File

@@ -1,69 +1,39 @@
package com.github.gtache.autosubtitle.gui.setup; package com.github.gtache.autosubtitle.gui.setup;
import com.github.gtache.autosubtitle.ToolType;
/** /**
* Controller for the setup view * Controller for the setup view
*/ */
public interface SetupController { public interface SetupController {
/** /**
* Installs the video converter * Installs the tool given by the tool type
*
* @param type The tool type
*/ */
void installVideoConverter(); void install(ToolType type);
/** /**
* Uninstalls the video converter * Uninstalls the tool given by the tool type
*
* @param type The tool type
*/ */
void uninstallVideoConverter(); void uninstall(ToolType type);
/** /**
* Updates the video converter * Updates the tool given by the tool type
*
* @param type The tool type
*/ */
void updateVideoConverter(); void update(ToolType type);
/** /**
* Reinstalls the video converter * Reinstalls the tool given by the tool type
*
* @param type The tool type
*/ */
void reinstallVideoConverter(); void reinstall(ToolType type);
/**
* Installs the subtitle extractor
*/
void installSubtitleExtractor();
/**
* Uninstalls the subtitle extractor
*/
void uninstallSubtitleExtractor();
/**
* Updates the subtitle extractor
*/
void updateSubtitleExtractor();
/**
* Reinstalls the subtitle extractor
*/
void reinstallSubtitleExtractor();
/**
* Installs the translator
*/
void installTranslator();
/**
* Uninstalls the translator
*/
void uninstallTranslator();
/**
* Updates the translator
*/
void updateTranslator();
/**
* Reinstalls the translator
*/
void reinstallTranslator();
/** /**
* @return the model * @return the model

View File

@@ -1,117 +1,101 @@
package com.github.gtache.autosubtitle.gui.setup; package com.github.gtache.autosubtitle.gui.setup;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.SetupStatus; import com.github.gtache.autosubtitle.setup.SetupStatus;
import java.util.List;
/** /**
* Model for the setup view * Model for the setup view
*/ */
public interface SetupModel { public interface SetupModel {
/** /**
* @return the status of the subtitle extractor * Returns the list of available setup managers for the given tool type
*
* @param type The tool type
* @return The list of managers
*/ */
SetupStatus subtitleExtractorStatus(); List<SetupManager> availableSetupManagers(ToolType type);
/** /**
* Sets the status of the subtitle extractor * Returns the selected setup manager for the given tool type
* *
* @param type The tool type
* @return The manager
*/
SetupManager selectedSetupManager(ToolType type);
/**
* Sets the selected setup manager for the given tool type
*
* @param type The tool type
* @param manager the new subtitle extractor
*/
void setSelectedSetupManager(ToolType type, SetupManager manager);
/**
* Returns the selected tool for the given tool type
*
* @param type The tool type
* @return the selected tool
*/
String selectedTool(ToolType type);
/**
* Returns the status of the setup manager for the given tool type
*
* @param type The tool type
* @return the status of the setup manager
*/
SetupStatus managerStatus(ToolType type);
/**
* Sets the status of the setup manager for the given tool type
*
* @param type The tool type
* @param status the new status * @param status the new status
*/ */
void setSubtitleExtractorStatus(SetupStatus status); void setManagerStatus(ToolType type, SetupStatus status);
/** /**
* @return the progress of the subtitle extractor setup * Returns the progress of the tool setup for the given tool type
*/
double subtitleExtractorSetupProgress();
/**
* Sets the progress of the subtitle extractor setup
* *
* @param type The tool type
* @return the progress of the tool setup
*/
double setupProgress(ToolType type);
/**
* Sets the progress of the tool setup for the given tool type
*
* @param type The tool type
* @param progress the new progress * @param progress the new progress
*/ */
void setSubtitleExtractorSetupProgress(double progress); void setSetupProgress(ToolType type, double progress);
/** /**
* @return the text of the subtitle extractor setup progress * Returns the text of the setup progress for the given tool type
*/
String subtitleExtractorSetupProgressLabel();
/**
* Sets the text of the subtitle extractor setup progress
* *
* @param type The tool type
* @return the text of the setup progress label
*/
String setupProgressLabel(ToolType type);
/**
* Sets the text of the setup progress for the given tool type
*
* @param type The tool type
* @param label the new text * @param label the new text
*/ */
void setSubtitleExtractorSetupProgressLabel(String label); void setSetupProgressLabel(ToolType type, String label);
/** /**
* @return the status of the video converter * Returns true if the setup is editable
*/
SetupStatus videoConverterStatus();
/**
* Sets the status of the video converter
* *
* @param status the new status * @param type The tool type
* @return true if the setup is editable
*/ */
void setVideoConverterStatus(SetupStatus status); boolean isSetupInProgress(ToolType type);
/**
* @return the progress of the video converter setup
*/
double videoConverterSetupProgress();
/**
* Sets the progress of the video converter setup
*
* @param progress the new progress
*/
void setVideoConverterSetupProgress(double progress);
/**
* @return the text of the video converter setup progress
*/
String videoConverterSetupProgressLabel();
/**
* Sets the text of the video converter setup progress
*
* @param label the new text
*/
void setVideoConverterSetupProgressLabel(String label);
/**
* @return the status of the translator
*/
SetupStatus translatorStatus();
/**
* Sets the status of the translator
*
* @param status the new status
*/
void setTranslatorStatus(SetupStatus status);
/**
* @return the progress of the translator setup
*/
double translatorSetupProgress();
/**
* Sets the progress of the translator setup
*
* @param progress the new progress
*/
void setTranslatorSetupProgress(double progress);
/**
* @return the text of the translator setup progress
*/
String translatorSetupProgressLabel();
/**
* Sets the text of the translator setup progress
*
* @param label the new text
*/
void setTranslatorSetupProgressLabel(String label);
} }

View File

@@ -26,7 +26,10 @@ setup.status.installed.label=is installed.
setup.status.not_installed.label=is not installed. setup.status.not_installed.label=is not installed.
setup.status.system_installed.label=is installed (system). setup.status.system_installed.label=is installed (system).
setup.status.update_available.label=has an available update. setup.status.update_available.label=has an available update.
setup.subtitle_extractor.choice.label=Subtitle extractor
setup.subtitle_translator.choice.label=Subtitle translator
setup.uninstall.error.label=An error occurred while uninstalling : {0} setup.uninstall.error.label=An error occurred while uninstalling : {0}
setup.uninstall.error.title=Error uninstalling setup.uninstall.error.title=Error uninstalling
setup.update.error.label=An error occurred while updating : {0} setup.update.error.label=An error occurred while updating : {0}
setup.update.error.title=Error updating setup.update.error.title=Error updating
setup.video_converter.choice.label=Video Converter

View File

@@ -1,3 +1,4 @@
setup.converter.choice.label=Convertisseur vid\u00E9o
setup.description.label=Statut des outils utilis\u00E9s par l'application setup.description.label=Statut des outils utilis\u00E9s par l'application
setup.event.check.end.label=Contr\u00F4le de {0} termin\u00E9 setup.event.check.end.label=Contr\u00F4le de {0} termin\u00E9
setup.event.check.start.label=Contr\u00F4le de {0} en cours setup.event.check.start.label=Contr\u00F4le de {0} en cours
@@ -11,6 +12,7 @@ setup.event.uninstall.end.label=D\u00E9sinstallation de {0} termin\u00E9e
setup.event.uninstall.start.label=D\u00E9sinstallation de {0} en cours setup.event.uninstall.start.label=D\u00E9sinstallation de {0} en cours
setup.event.update.end.label=Mise \u00E0 jour de {0} termin\u00E9e setup.event.update.end.label=Mise \u00E0 jour de {0} termin\u00E9e
setup.event.update.start.label=Mise \u00E0 jour de {0} en cours setup.event.update.start.label=Mise \u00E0 jour de {0} en cours
setup.extractor.choice.label=Extracteur de sous-titres
setup.install.error.label=Une erreur s''est produite lors de l''installation: {0} setup.install.error.label=Une erreur s''est produite lors de l''installation: {0}
setup.install.error.title=Erreur d'installation setup.install.error.title=Erreur d'installation
setup.menu.install.label=Installer setup.menu.install.label=Installer
@@ -26,7 +28,11 @@ setup.status.installed.label=est install\u00E9.
setup.status.not_installed.label=n'est pas install\u00E9. setup.status.not_installed.label=n'est pas install\u00E9.
setup.status.system_installed.label=est install\u00E9 (syst\u00E8me). setup.status.system_installed.label=est install\u00E9 (syst\u00E8me).
setup.status.update_available.label=a une mise \u00E0 jour disponible. setup.status.update_available.label=a une mise \u00E0 jour disponible.
setup.subtitle_extractor.choice.label=Extracteur de sous-titres
setup.subtitle_translator.choice.label=Traducteur de sous-titres
setup.translator.choice.label=Traducteur de sous-titres
setup.uninstall.error.label=Une erreur s''est produite lors de la d\u00E9sinstallation : {0} setup.uninstall.error.label=Une erreur s''est produite lors de la d\u00E9sinstallation : {0}
setup.uninstall.error.title=Erreur de d\u00E9sinstallation setup.uninstall.error.title=Erreur de d\u00E9sinstallation
setup.update.error.label=Une erreur s''est produite lors de la mise \u00E0 jour : {0} setup.update.error.label=Une erreur s''est produite lors de la mise \u00E0 jour : {0}
setup.update.error.title=Erreur de mise \u00E0 jour setup.update.error.title=Erreur de mise \u00E0 jour
setup.video_converter.choice.label=Convertisseur de vid\u00E9o

View File

@@ -13,7 +13,7 @@
<properties> <properties>
<controlsfx.version>11.2.1</controlsfx.version> <controlsfx.version>11.2.1</controlsfx.version>
<javafx.version>22.0.2</javafx.version> <javafx.version>23</javafx.version>
<testfx.version>4.0.18</testfx.version> <testfx.version>4.0.18</testfx.version>
</properties> </properties>

View File

@@ -60,7 +60,6 @@ public class FXMediaController implements MediaController {
private Label volumeValueLabel; private Label volumeValueLabel;
private final FXMediaModel model; private final FXMediaModel model;
private final FXMediaBinder binder;
private final TimeFormatter timeFormatter; private final TimeFormatter timeFormatter;
private final Image playImage; private final Image playImage;
private final Image pauseImage; private final Image pauseImage;
@@ -71,10 +70,10 @@ public class FXMediaController implements MediaController {
FXMediaController(final FXMediaModel model, final FXMediaBinder binder, final TimeFormatter timeFormatter, FXMediaController(final FXMediaModel model, final FXMediaBinder binder, final TimeFormatter timeFormatter,
@Play final Image playImage, @Pause final Image pauseImage) { @Play final Image playImage, @Pause final Image pauseImage) {
this.model = requireNonNull(model); this.model = requireNonNull(model);
this.binder = requireNonNull(binder);
this.timeFormatter = requireNonNull(timeFormatter); this.timeFormatter = requireNonNull(timeFormatter);
this.playImage = requireNonNull(playImage); this.playImage = requireNonNull(playImage);
this.pauseImage = requireNonNull(pauseImage); this.pauseImage = requireNonNull(pauseImage);
binder.createBindings();
} }
@FXML @FXML
@@ -116,7 +115,6 @@ public class FXMediaController implements MediaController {
stackPane.widthProperty().addListener((observable, oldValue, newValue) -> resizeMediaView()); stackPane.widthProperty().addListener((observable, oldValue, newValue) -> resizeMediaView());
stackPane.heightProperty().addListener((observable, oldValue, newValue) -> resizeMediaView()); stackPane.heightProperty().addListener((observable, oldValue, newValue) -> resizeMediaView());
binder.createBindings();
} }
private void resizeMediaView() { private void resizeMediaView() {

View File

@@ -0,0 +1,35 @@
package com.github.gtache.autosubtitle.gui.parameters.fx;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.gui.fx.FXBinder;
import com.github.gtache.autosubtitle.gui.setup.fx.FXSetupModel;
import javax.inject.Inject;
import javax.inject.Singleton;
import static java.util.Objects.requireNonNull;
/**
* Binds the subtitles model
*/
@Singleton
public class FXParametersBinder implements FXBinder {
private final FXParametersModel parametersModel;
private final FXSetupModel setupModel;
@Inject
FXParametersBinder(final FXParametersModel parametersModel, final FXSetupModel setupModel) {
this.parametersModel = requireNonNull(parametersModel);
this.setupModel = requireNonNull(setupModel);
}
@Override
public void createBindings() {
setupModel.selectedToolProperty(ToolType.SUBTITLE_EXTRACTOR).addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
parametersModel.extractionModelProviderProperty().set(parametersModel.availableExtractionModelProviders().get(newValue));
}
});
}
}

View File

@@ -4,7 +4,7 @@ import com.github.gtache.autosubtitle.gui.fx.AbstractFXController;
import com.github.gtache.autosubtitle.gui.parameters.ParametersController; import com.github.gtache.autosubtitle.gui.parameters.ParametersController;
import com.github.gtache.autosubtitle.subtitle.OutputFormat; import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider; import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter; import javafx.scene.control.TextFormatter;
@@ -47,13 +47,12 @@ public class FXParametersController extends AbstractFXController implements Para
private final FXParametersModel model; private final FXParametersModel model;
private final Preferences preferences; private final Preferences preferences;
private final ExtractionModelProvider extractionModelProvider;
@Inject @Inject
FXParametersController(final FXParametersModel model, final Preferences preferences, final ExtractionModelProvider extractionModelProvider) { FXParametersController(final FXParametersModel model, final FXParametersBinder binder, final Preferences preferences) {
this.model = requireNonNull(model); this.model = requireNonNull(model);
this.preferences = requireNonNull(preferences); this.preferences = requireNonNull(preferences);
this.extractionModelProvider = requireNonNull(extractionModelProvider); binder.createBindings();
} }
@FXML @FXML
@@ -83,17 +82,31 @@ public class FXParametersController extends AbstractFXController implements Para
maxLinesField.textProperty().bindBidirectional(model.maxLinesProperty(), new NumberStringConverter()); maxLinesField.textProperty().bindBidirectional(model.maxLinesProperty(), new NumberStringConverter());
loadPreferences(); loadPreferences();
model.extractionModelProviderProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
final var name = newValue.getClass().getSimpleName();
Platform.runLater(() -> {
final var modelName = preferences.get(name + ".extractionModel", model.extractionModel().name());
final var loadedModel = newValue.getExtractionModel(modelName);
model.setExtractionModel(loadedModel);
});
}
});
} }
private void loadPreferences() { private void loadPreferences() {
final var extractionModel = preferences.get("extractionModel", model.extractionModel().name());
final var outputFormat = preferences.get("outputFormat", model.outputFormat().name()); final var outputFormat = preferences.get("outputFormat", model.outputFormat().name());
final var fontFamily = preferences.get("fontName", model.fontName()); final var fontFamily = preferences.get("fontName", model.fontName());
final var fontSize = preferences.getInt("fontSize", model.fontSize()); final var fontSize = preferences.getInt("fontSize", model.fontSize());
final var maxLineLength = preferences.getInt("maxLineLength", model.maxLineLength()); final var maxLineLength = preferences.getInt("maxLineLength", model.maxLineLength());
final var maxLines = preferences.getInt("maxLines", model.maxLines()); final var maxLines = preferences.getInt("maxLines", model.maxLines());
model.setExtractionModel(extractionModelProvider.getExtractionModel(extractionModel)); final var extractionModelProvider = model.extractionModelProviderProperty().get();
final var name = extractionModelProvider.getClass().getSimpleName();
final var modelName = preferences.get(name + ".extractionModel", model.extractionModel().name());
model.setExtractionModel(extractionModelProvider.getExtractionModel(modelName));
model.setOutputFormat(OutputFormat.valueOf(outputFormat)); model.setOutputFormat(OutputFormat.valueOf(outputFormat));
model.setFontName(fontFamily); model.setFontName(fontFamily);
model.setFontSize(fontSize); model.setFontSize(fontSize);
@@ -106,7 +119,7 @@ public class FXParametersController extends AbstractFXController implements Para
@Override @Override
public void save() { public void save() {
logger.info("Saving preferences"); logger.info("Saving preferences");
preferences.put("extractionModel", model.extractionModel().name()); preferences.put(model.extractionModelProviderProperty().get().getClass().getSimpleName() + ".extractionModel", model.extractionModel().name());
preferences.put("outputFormat", model.outputFormat().name()); preferences.put("outputFormat", model.outputFormat().name());
preferences.put("fontName", model.fontName()); preferences.put("fontName", model.fontName());
preferences.putInt("fontSize", model.fontSize()); preferences.putInt("fontSize", model.fontSize());

View File

@@ -21,9 +21,11 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Map;
/** /**
* FX implementation of {@link ParametersModel} * FX implementation of {@link ParametersModel}
@@ -31,6 +33,8 @@ import javax.inject.Singleton;
@Singleton @Singleton
public class FXParametersModel implements ParametersModel { public class FXParametersModel implements ParametersModel {
private final ObservableMap<String, ExtractionModelProvider> availableExtractionModelProviders;
private final ObjectProperty<ExtractionModelProvider> extractionModelProvider;
private final ObservableList<ExtractionModel> availableExtractionModels; private final ObservableList<ExtractionModel> availableExtractionModels;
private final ObjectProperty<ExtractionModel> extractionModel; private final ObjectProperty<ExtractionModel> extractionModel;
private final ObservableList<OutputFormat> availableOutputFormats; private final ObservableList<OutputFormat> availableOutputFormats;
@@ -43,10 +47,12 @@ public class FXParametersModel implements ParametersModel {
private final IntegerProperty maxLines; private final IntegerProperty maxLines;
@Inject @Inject
FXParametersModel(final ExtractionModelProvider extractionModelProvider, @FontName final String defaultFontFamily, FXParametersModel(final Map<String, ExtractionModelProvider> extractionModelProviders, final ExtractionModelProvider defaultProvider, @FontName final String defaultFontFamily,
@FontSize final int defaultFontSize, @MaxLineLength final int defaultMaxLineLength, @MaxLines final int defaultMaxLines) { @FontSize final int defaultFontSize, @MaxLineLength final int defaultMaxLineLength, @MaxLines final int defaultMaxLines) {
this.availableExtractionModels = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(extractionModelProvider.getAvailableExtractionModels())); this.availableExtractionModelProviders = FXCollections.unmodifiableObservableMap(FXCollections.observableMap(extractionModelProviders));
this.extractionModel = new SimpleObjectProperty<>(extractionModelProvider.getDefaultExtractionModel()); this.extractionModelProvider = new SimpleObjectProperty<>(defaultProvider);
this.availableExtractionModels = FXCollections.observableArrayList(defaultProvider.getAvailableExtractionModels());
this.extractionModel = new SimpleObjectProperty<>(defaultProvider.getDefaultExtractionModel());
this.availableOutputFormats = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(OutputFormat.SRT)); this.availableOutputFormats = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(OutputFormat.SRT));
this.outputFormat = new SimpleObjectProperty<>(OutputFormat.SRT); this.outputFormat = new SimpleObjectProperty<>(OutputFormat.SRT);
this.availableFontFamilies = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList("Arial")); this.availableFontFamilies = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList("Arial"));
@@ -57,6 +63,12 @@ public class FXParametersModel implements ParametersModel {
this.maxLines = new SimpleIntegerProperty(defaultMaxLines); this.maxLines = new SimpleIntegerProperty(defaultMaxLines);
font.bind(Bindings.createObjectBinding(() -> new FontImpl(fontName(), fontSize()), fontName, fontSize)); font.bind(Bindings.createObjectBinding(() -> new FontImpl(fontName(), fontSize()), fontName, fontSize));
extractionModelProvider.addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
availableExtractionModels.setAll(newValue.getAvailableExtractionModels());
extractionModel.set(newValue.getDefaultExtractionModel());
}
});
} }
@Override @Override
@@ -166,4 +178,12 @@ public class FXParametersModel implements ParametersModel {
public IntegerProperty maxLinesProperty() { public IntegerProperty maxLinesProperty() {
return maxLines; return maxLines;
} }
ObservableMap<String, ExtractionModelProvider> availableExtractionModelProviders() {
return availableExtractionModelProviders;
}
ObjectProperty<ExtractionModelProvider> extractionModelProviderProperty() {
return extractionModelProvider;
}
} }

View File

@@ -1,10 +1,8 @@
package com.github.gtache.autosubtitle.gui.setup.fx; package com.github.gtache.autosubtitle.gui.setup.fx;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.gui.fx.AbstractFXController; import com.github.gtache.autosubtitle.gui.fx.AbstractFXController;
import com.github.gtache.autosubtitle.gui.setup.SetupController; import com.github.gtache.autosubtitle.gui.setup.SetupController;
import com.github.gtache.autosubtitle.modules.setup.impl.SubtitleExtractorSetup;
import com.github.gtache.autosubtitle.modules.setup.impl.TranslatorSetup;
import com.github.gtache.autosubtitle.modules.setup.impl.VideoConverterSetup;
import com.github.gtache.autosubtitle.setup.SetupEvent; import com.github.gtache.autosubtitle.setup.SetupEvent;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupListener; import com.github.gtache.autosubtitle.setup.SetupListener;
@@ -12,26 +10,29 @@ import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.SetupStatus; import com.github.gtache.autosubtitle.setup.SetupStatus;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.MenuButton; import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressBar; import javafx.scene.control.ProgressBar;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Window; import javafx.stage.Window;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.controlsfx.control.PrefixSelectionComboBox;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.HashMap; import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import static java.util.Objects.requireNonNull;
/** /**
* FX implementation of {@link SetupController} * FX implementation of {@link SetupController}
@@ -41,233 +42,81 @@ public class FXSetupController extends AbstractFXController implements SetupCont
private static final Logger logger = LogManager.getLogger(FXSetupController.class); private static final Logger logger = LogManager.getLogger(FXSetupController.class);
@FXML
private GridPane setupGrid;
@FXML @FXML
private ResourceBundle resources; private ResourceBundle resources;
@FXML
private Label converterNameLabel;
@FXML
private Label converterStatusLabel;
@FXML
private Label extractorNameLabel;
@FXML
private Label extractorStatusLabel;
@FXML
private Label translatorNameLabel;
@FXML
private Label translatorStatusLabel;
@FXML
private MenuButton converterButton;
@FXML
private MenuButton extractorButton;
@FXML
private MenuButton translatorButton;
@FXML
private ProgressBar converterProgress;
@FXML
private ProgressBar extractorProgress;
@FXML
private ProgressBar translatorProgress;
@FXML
private Label converterProgressLabel;
@FXML
private Label extractorProgressLabel;
@FXML
private Label translatorProgressLabel;
private final FXSetupModel model; private final FXSetupModel model;
private final SetupManager converterManager; private final Preferences preferences;
private final SetupManager extractorManager;
private final SetupManager translatorManager;
private final Map<SetupManager, ObjectProperty<SetupStatus>> statusMap;
private final Map<SetupManager, StringProperty> setupProgressMessageMap;
private final Map<SetupManager, DoubleProperty> setupProgressMap;
@Inject @Inject
FXSetupController(final FXSetupModel model, FXSetupController(final FXSetupModel model, final Preferences preferences) {
@VideoConverterSetup final SetupManager converterManager, this.model = requireNonNull(model);
@SubtitleExtractorSetup final SetupManager extractorManager, this.preferences = requireNonNull(preferences);
@TranslatorSetup final SetupManager translatorManager) {
this.model = Objects.requireNonNull(model);
this.converterManager = Objects.requireNonNull(converterManager);
this.extractorManager = Objects.requireNonNull(extractorManager);
this.translatorManager = Objects.requireNonNull(translatorManager);
statusMap = HashMap.newHashMap(3);
setupProgressMessageMap = HashMap.newHashMap(3);
setupProgressMap = HashMap.newHashMap(3);
} }
@FXML @FXML
void initialize() { void initialize() {
statusMap.put(converterManager, model.videoConverterStatusProperty()); createGridRows();
statusMap.put(extractorManager, model.subtitleExtractorStatusProperty()); Arrays.stream(ToolType.values()).forEach(t -> model.selectedToolProperty(t)
statusMap.put(translatorManager, model.translatorStatusProperty()); .addListener((observable, oldValue, newValue) -> saveSelectedTool(t, newValue)));
setupProgressMessageMap.put(converterManager, model.videoConverterSetupProgressLabelProperty()); loadPreferences();
setupProgressMessageMap.put(extractorManager, model.subtitleExtractorSetupProgressLabelProperty());
setupProgressMessageMap.put(translatorManager, model.translatorSetupProgressLabelProperty());
setupProgressMap.put(converterManager, model.videoConverterSetupProgressProperty());
setupProgressMap.put(extractorManager, model.subtitleExtractorSetupProgressProperty());
setupProgressMap.put(translatorManager, model.translatorSetupProgressProperty());
bindMenu(converterButton, converterManager);
bindMenu(extractorButton, extractorManager);
bindMenu(translatorButton, translatorManager);
model.setSubtitleExtractorStatus(extractorManager.status());
model.setVideoConverterStatus(converterManager.status());
model.setTranslatorStatus(translatorManager.status());
converterNameLabel.setText(converterManager.name());
extractorNameLabel.setText(extractorManager.name());
translatorNameLabel.setText(translatorManager.name());
bindLabelStatus(converterStatusLabel, model.videoConverterStatusProperty());
bindLabelStatus(extractorStatusLabel, model.subtitleExtractorStatusProperty());
bindLabelStatus(translatorStatusLabel, model.translatorStatusProperty());
converterProgress.progressProperty().bindBidirectional(model.videoConverterSetupProgressProperty());
extractorProgress.progressProperty().bindBidirectional(model.subtitleExtractorSetupProgressProperty());
translatorProgress.progressProperty().bindBidirectional(model.translatorSetupProgressProperty());
converterProgress.visibleProperty().bind(model.videoConverterSetupProgressProperty().greaterThan(-2));
extractorProgress.visibleProperty().bind(model.subtitleExtractorSetupProgressProperty().greaterThan(-2));
translatorProgress.visibleProperty().bind(model.translatorSetupProgressProperty().greaterThan(-2));
converterProgressLabel.textProperty().bind(model.videoConverterSetupProgressLabelProperty());
extractorProgressLabel.textProperty().bind(model.subtitleExtractorSetupProgressLabelProperty());
translatorProgressLabel.textProperty().bind(model.translatorSetupProgressLabelProperty());
converterProgressLabel.visibleProperty().bind(converterProgress.visibleProperty());
extractorProgressLabel.visibleProperty().bind(extractorProgress.visibleProperty());
translatorProgressLabel.visibleProperty().bind(translatorProgress.visibleProperty());
} }
private void bindMenu(final MenuButton button, final SetupManager setupManager) { private void saveSelectedTool(final ToolType type, final String value) {
button.disableProperty().bind(Bindings.isEmpty(button.getItems())); if (value != null) {
statusMap.get(setupManager).addListener((observable, oldValue, newValue) -> { preferences.put(type.name(), value);
button.getItems().clear(); try {
switch (newValue) { preferences.flush();
case NOT_INSTALLED -> { } catch (final BackingStoreException e) {
final var installItem = new MenuItem(resources.getString("setup.menu.install.label")); logger.error("Error saving preferences", e);
installItem.setOnAction(e -> tryInstall(setupManager));
button.getItems().add(installItem);
}
case BUNDLE_INSTALLED -> {
final var reinstallItem = new MenuItem(resources.getString("setup.menu.reinstall.label"));
reinstallItem.setOnAction(e -> tryReinstall(setupManager));
final var uninstallItem = new MenuItem(resources.getString("setup.menu.uninstall.label"));
uninstallItem.setOnAction(e -> tryUninstall(setupManager));
button.getItems().addAll(reinstallItem, uninstallItem);
}
case UPDATE_AVAILABLE -> {
final var updateItem = new MenuItem(resources.getString("setup.menu.update.label"));
updateItem.setOnAction(e -> tryUpdate(setupManager));
final var reinstallItem = new MenuItem(resources.getString("setup.menu.reinstall.label"));
reinstallItem.setOnAction(e -> tryReinstall(setupManager));
final var uninstallItem = new MenuItem(resources.getString("setup.menu.uninstall.label"));
uninstallItem.setOnAction(e -> tryUninstall(setupManager));
button.getItems().addAll(updateItem, reinstallItem, uninstallItem);
}
case null, default -> {
// Do nothing, buttons are cleared
} }
} }
});
} }
private void bindLabelStatus(final Label label, final ObjectProperty<SetupStatus> status) { private void loadPreferences() {
label.textProperty().bind(Bindings.createStringBinding(() -> resources.getString("setup.status." + status.get().name().toLowerCase() + ".label"), status)); for (final var type : ToolType.values()) {
final var value = preferences.get(type.name(), model.selectedTool(type));
model.selectedToolProperty(type).set(value);
}
} }
@Override @Override
public void installVideoConverter() { public void install(final ToolType type) {
tryInstall(converterManager); trySetup(type, SetupManager::install, "install");
} }
@Override @Override
public void uninstallVideoConverter() { public void uninstall(final ToolType type) {
tryUninstall(converterManager); trySetup(type, SetupManager::uninstall, "uninstall");
} }
@Override @Override
public void updateVideoConverter() { public void update(final ToolType type) {
tryUpdate(converterManager); trySetup(type, SetupManager::update, "update");
} }
@Override @Override
public void reinstallVideoConverter() { public void reinstall(final ToolType type) {
tryReinstall(converterManager); trySetup(type, SetupManager::reinstall, "reinstall");
} }
@Override private void trySetup(final ToolType type, final SetupConsumer consumer, final String operation) {
public void installSubtitleExtractor() { final var manager = model.selectedSetupManager(type);
tryInstall(extractorManager);
}
@Override
public void uninstallSubtitleExtractor() {
tryUninstall(extractorManager);
}
@Override
public void updateSubtitleExtractor() {
tryUpdate(extractorManager);
}
@Override
public void reinstallSubtitleExtractor() {
tryReinstall(extractorManager);
}
@Override
public void installTranslator() {
tryInstall(translatorManager);
}
@Override
public void uninstallTranslator() {
tryUninstall(translatorManager);
}
@Override
public void updateTranslator() {
tryUpdate(translatorManager);
}
@Override
public void reinstallTranslator() {
tryReinstall(translatorManager);
}
private void tryInstall(final SetupManager manager) {
trySetup(manager, SetupManager::install, "install");
}
private void tryUninstall(final SetupManager manager) {
trySetup(manager, SetupManager::uninstall, "uninstall");
}
private void tryReinstall(final SetupManager manager) {
trySetup(manager, SetupManager::reinstall, "reinstall");
}
private void tryUpdate(final SetupManager manager) {
trySetup(manager, SetupManager::update, "update");
}
private void trySetup(final SetupManager manager, final SetupConsumer consumer, final String operation) {
manager.addListener(this); manager.addListener(this);
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
consumer.accept(manager); consumer.accept(manager);
Platform.runLater(() -> { Platform.runLater(() -> {
statusMap.get(manager).set(manager.status()); model.setManagerStatus(type, manager.status());
setupProgressMap.get(manager).set(-2); model.setSetupProgress(type, -2);
}); });
} catch (final SetupException e) { } catch (final SetupException e) {
logger.error("Error {}ing {}", operation, manager.name(), e); logger.error("Error {}ing {}", operation, manager.name(), e);
Platform.runLater(() -> { Platform.runLater(() -> {
statusMap.get(manager).set(SetupStatus.ERRORED); model.setManagerStatus(type, SetupStatus.ERRORED);
setupProgressMap.get(manager).set(-2); model.setSetupProgress(type, -2);
showErrorDialog(resources.getString("setup." + operation + ".error.title"), showErrorDialog(resources.getString("setup." + operation + ".error.title"),
MessageFormat.format(resources.getString("setup." + operation + ".error.label"), e.getMessage())); MessageFormat.format(resources.getString("setup." + operation + ".error.label"), e.getMessage()));
}); });
@@ -300,15 +149,105 @@ public class FXSetupController extends AbstractFXController implements SetupCont
private void onAction(final SetupEvent event, final String display) { private void onAction(final SetupEvent event, final String display) {
final var manager = event.setupManager(); final var manager = event.setupManager();
final var property = setupProgressMessageMap.get(manager); final var type = manager.type();
final var progress = event.progress(); final var progress = event.progress();
final var progressProperty = setupProgressMap.get(manager);
Platform.runLater(() -> { Platform.runLater(() -> {
property.set(display); model.setSetupProgressLabel(type, display);
progressProperty.set(progress); model.setSetupProgress(type, progress);
}); });
} }
private void createGridRows() {
for (final var value : ToolType.values()) {
createGridRow(value);
}
}
private void createGridRow(final ToolType type) {
if (!model.availableSetupManagers(type).isEmpty()) {
createSelectionRow(type);
createProgressRow(type);
}
}
private void createSelectionRow(final ToolType type) {
final var label = new Label(resources.getString("setup." + type.name().toLowerCase() + ".choice.label"));
final var comboBox = new PrefixSelectionComboBox<SetupManager>();
comboBox.setItems(model.availableSetupManagers(type));
comboBox.setConverter(new SetupManagerStringConverter());
comboBox.valueProperty().bindBidirectional(model.selectedSetupManagerProperty(type));
comboBox.disableProperty().bind(model.setupInProgressProperty(type));
final var rowIndex = setupGrid.getRowCount() - 1;
final var constraints = new RowConstraints();
constraints.setFillHeight(true);
constraints.setVgrow(Priority.SOMETIMES);
setupGrid.getRowConstraints().add(rowIndex, constraints);
setupGrid.add(label, 0, rowIndex);
setupGrid.add(comboBox, 1, rowIndex);
}
private void createProgressRow(final ToolType type) {
final var statusLabel = new Label();
final var installationButton = new MenuButton(resources.getString("setup.menu.label"));
final var progressBar = new ProgressBar();
final var progressLabel = new Label();
statusLabel.textProperty().bind(model.managerStatusProperty(type).map(s -> resources.getString("setup.status." + s.name().toLowerCase() + ".label")));
progressLabel.textProperty().bind(model.setupProgressLabelProperty(type));
progressLabel.visibleProperty().bind(model.setupInProgressProperty(type));
progressBar.progressProperty().bind(model.setupProgressProperty(type));
progressBar.visibleProperty().bind(model.setupInProgressProperty(type));
installationButton.disableProperty().bind(model.setupInProgressProperty(type).or(Bindings.isEmpty(installationButton.getItems())));
bindMenu(installationButton, type);
fillMenu(installationButton, type);
final var rowIndex = setupGrid.getRowCount() - 1;
final var constraints = new RowConstraints();
constraints.setFillHeight(true);
constraints.setVgrow(Priority.SOMETIMES);
setupGrid.getRowConstraints().add(rowIndex, constraints);
setupGrid.add(statusLabel, 1, rowIndex);
setupGrid.add(installationButton, 2, rowIndex);
setupGrid.add(progressBar, 3, rowIndex);
setupGrid.add(progressLabel, 4, rowIndex);
}
private void bindMenu(final MenuButton button, final ToolType type) {
model.managerStatusProperty(type).addListener((observable, oldValue, newValue) -> fillMenu(button, type));
}
private void fillMenu(final MenuButton button, final ToolType type) {
final var value = model.managerStatus(type);
button.getItems().clear();
switch (value) {
case NOT_INSTALLED -> {
final var installItem = new MenuItem(resources.getString("setup.menu.install.label"));
installItem.setOnAction(e -> install(type));
button.getItems().add(installItem);
}
case BUNDLE_INSTALLED -> {
final var reinstallItem = new MenuItem(resources.getString("setup.menu.reinstall.label"));
reinstallItem.setOnAction(e -> reinstall(type));
final var uninstallItem = new MenuItem(resources.getString("setup.menu.uninstall.label"));
uninstallItem.setOnAction(e -> uninstall(type));
button.getItems().addAll(reinstallItem, uninstallItem);
}
case UPDATE_AVAILABLE -> {
final var updateItem = new MenuItem(resources.getString("setup.menu.update.label"));
updateItem.setOnAction(e -> update(type));
final var reinstallItem = new MenuItem(resources.getString("setup.menu.reinstall.label"));
reinstallItem.setOnAction(e -> reinstall(type));
final var uninstallItem = new MenuItem(resources.getString("setup.menu.uninstall.label"));
uninstallItem.setOnAction(e -> uninstall(type));
button.getItems().addAll(updateItem, reinstallItem, uninstallItem);
}
case null, default -> {
// Do nothing, buttons are cleared
}
}
}
@FunctionalInterface @FunctionalInterface
private interface SetupConsumer { private interface SetupConsumer {
void accept(SetupManager manager) throws SetupException; void accept(SetupManager manager) throws SetupException;
@@ -321,6 +260,7 @@ public class FXSetupController extends AbstractFXController implements SetupCont
@Override @Override
public Window window() { public Window window() {
return converterNameLabel.getScene().getWindow(); return setupGrid.getScene().getWindow();
} }
} }

View File

@@ -1,16 +1,25 @@
package com.github.gtache.autosubtitle.gui.setup.fx; package com.github.gtache.autosubtitle.gui.setup.fx;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.gui.setup.SetupModel; import com.github.gtache.autosubtitle.gui.setup.SetupModel;
import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.SetupStatus; import com.github.gtache.autosubtitle.setup.SetupStatus;
import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Collection;
import java.util.Map;
/** /**
* FX implementation of {@link SetupModel} * FX implementation of {@link SetupModel}
@@ -18,152 +27,146 @@ import javax.inject.Singleton;
@Singleton @Singleton
public class FXSetupModel implements SetupModel { public class FXSetupModel implements SetupModel {
private final ObjectProperty<SetupStatus> subtitleExtractorStatus; private final ObservableMap<ToolType, ObservableList<SetupManager>> availableSetupManagers;
private final DoubleProperty subtitleExtractorSetupProgress; private final ObservableMap<ToolType, StringProperty> selectedTools;
private final StringProperty subtitleExtractorSetupProgressLabel; private final ObservableMap<ToolType, ObjectProperty<SetupManager>> selectedSetupManagers;
private final ObjectProperty<SetupStatus> videoConverterStatus; private final ObservableMap<ToolType, ObjectProperty<SetupStatus>> setupStatuses;
private final DoubleProperty videoConverterSetupProgress; private final ObservableMap<ToolType, DoubleProperty> setupProgresses;
private final StringProperty videoConverterSetupProgressLabel; private final ObservableMap<ToolType, StringProperty> setupProgressLabels;
private final ObjectProperty<SetupStatus> translatorStatus; private final ObservableMap<ToolType, ReadOnlyBooleanWrapper> setupInProgress;
private final DoubleProperty translatorSetupProgress;
private final StringProperty translatorSetupProgressLabel;
@Inject @Inject
FXSetupModel() { FXSetupModel(final Map<ToolType, Map<String, SetupManager>> setupManagers,
this.subtitleExtractorStatus = new SimpleObjectProperty<>(SetupStatus.ERRORED); final Map<ToolType, SetupManager> defaultManagers) {
this.subtitleExtractorSetupProgress = new SimpleDoubleProperty(-2); final var tmpAvailableSetupManagers = FXCollections.<ToolType, ObservableList<SetupManager>>observableHashMap();
this.subtitleExtractorSetupProgressLabel = new SimpleStringProperty(""); final var tmpSelectedTools = FXCollections.<ToolType, StringProperty>observableHashMap();
this.videoConverterStatus = new SimpleObjectProperty<>(SetupStatus.ERRORED); final var tmpSelectedSetupManagers = FXCollections.<ToolType, ObjectProperty<SetupManager>>observableHashMap();
this.videoConverterSetupProgress = new SimpleDoubleProperty(-2); final var tmpSetupStatuses = FXCollections.<ToolType, ObjectProperty<SetupStatus>>observableHashMap();
this.videoConverterSetupProgressLabel = new SimpleStringProperty(""); final var tmpSetupProgresses = FXCollections.<ToolType, DoubleProperty>observableHashMap();
this.translatorStatus = new SimpleObjectProperty<>(SetupStatus.ERRORED); final var tmpSetupProgressLabels = FXCollections.<ToolType, StringProperty>observableHashMap();
this.translatorSetupProgress = new SimpleDoubleProperty(-2); final var tmpSetupEditables = FXCollections.<ToolType, ReadOnlyBooleanWrapper>observableHashMap();
this.translatorSetupProgressLabel = new SimpleStringProperty(""); setupManagers.forEach((type, managers) -> {
tmpAvailableSetupManagers.put(type, getUnmodifiableObservableList(managers.values()));
tmpSelectedTools.put(type, new SimpleStringProperty(getKeyForValue(managers, defaultManagers.get(type))));
tmpSelectedSetupManagers.put(type, new SimpleObjectProperty<>());
tmpSetupStatuses.put(type, new SimpleObjectProperty<>(SetupStatus.ERRORED));
tmpSetupProgresses.put(type, new SimpleDoubleProperty(-2));
tmpSetupProgressLabels.put(type, new SimpleStringProperty(""));
tmpSetupEditables.put(type, new ReadOnlyBooleanWrapper(false));
});
this.availableSetupManagers = FXCollections.unmodifiableObservableMap(tmpAvailableSetupManagers);
this.selectedTools = FXCollections.unmodifiableObservableMap(tmpSelectedTools);
this.selectedSetupManagers = FXCollections.unmodifiableObservableMap(tmpSelectedSetupManagers);
this.setupStatuses = FXCollections.unmodifiableObservableMap(tmpSetupStatuses);
this.setupProgresses = FXCollections.unmodifiableObservableMap(tmpSetupProgresses);
this.setupProgressLabels = FXCollections.unmodifiableObservableMap(tmpSetupProgressLabels);
this.setupInProgress = FXCollections.unmodifiableObservableMap(tmpSetupEditables);
selectedSetupManagers.forEach((type, value) -> value.addListener((observable, oldValue, newValue) ->
{
setupStatuses.get(type).set(newValue == null ? SetupStatus.ERRORED : newValue.status());
selectedTools.get(type).set(newValue == null ?
getKeyForValue(setupManagers.get(type), defaultManagers.get(type)) :
getKeyForValue(setupManagers.get(type), newValue));
}));
selectedTools.forEach((type, value) -> value.addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
final var manager = setupManagers.get(type).get(newValue);
if (manager != null) {
setSelectedSetupManager(type, manager);
}
}
}));
setupInProgress.forEach((type, value) -> value.bind(setupProgresses.get(type).greaterThan(-2)));
defaultManagers.forEach(this::setSelectedSetupManager);
}
private static String getKeyForValue(final Map<String, ? extends SetupManager> managers, final SetupManager manager) {
return managers.entrySet().stream().filter(e -> e.getValue() == manager).findFirst().orElseThrow().getKey();
} }
@Override @Override
public SetupStatus subtitleExtractorStatus() { public ObservableList<SetupManager> availableSetupManagers(final ToolType type) {
return subtitleExtractorStatus.get(); return this.availableSetupManagers.getOrDefault(type, FXCollections.emptyObservableList());
} }
@Override @Override
public void setSubtitleExtractorStatus(final SetupStatus status) { public SetupManager selectedSetupManager(final ToolType type) {
subtitleExtractorStatus.set(status); return this.selectedSetupManagers.get(type).get();
}
ObjectProperty<SetupStatus> subtitleExtractorStatusProperty() {
return subtitleExtractorStatus;
} }
@Override @Override
public double subtitleExtractorSetupProgress() { public void setSelectedSetupManager(final ToolType type, final SetupManager manager) {
return subtitleExtractorSetupProgress.get(); this.selectedSetupManagers.get(type).set(manager);
}
ObjectProperty<SetupManager> selectedSetupManagerProperty(final ToolType type) {
return this.selectedSetupManagers.get(type);
} }
@Override @Override
public void setSubtitleExtractorSetupProgress(final double progress) { public String selectedTool(final ToolType type) {
subtitleExtractorSetupProgress.set(progress); return this.selectedTools.get(type).get();
} }
DoubleProperty subtitleExtractorSetupProgressProperty() { public StringProperty selectedToolProperty(final ToolType type) {
return subtitleExtractorSetupProgress; return this.selectedTools.get(type);
} }
@Override @Override
public String subtitleExtractorSetupProgressLabel() { public SetupStatus managerStatus(final ToolType type) {
return subtitleExtractorSetupProgressLabel.get(); return this.setupStatuses.get(type).get();
} }
@Override @Override
public void setSubtitleExtractorSetupProgressLabel(final String label) { public void setManagerStatus(final ToolType type, final SetupStatus status) {
subtitleExtractorSetupProgressLabel.set(label); this.setupStatuses.get(type).set(status);
} }
StringProperty subtitleExtractorSetupProgressLabelProperty() { ObjectProperty<SetupStatus> managerStatusProperty(final ToolType type) {
return subtitleExtractorSetupProgressLabel; return this.setupStatuses.get(type);
} }
@Override @Override
public SetupStatus videoConverterStatus() { public double setupProgress(final ToolType type) {
return videoConverterStatus.get(); return this.setupProgresses.get(type).get();
} }
@Override @Override
public void setVideoConverterStatus(final SetupStatus status) { public void setSetupProgress(final ToolType type, final double progress) {
videoConverterStatus.set(status); this.setupProgresses.get(type).set(progress);
} }
ObjectProperty<SetupStatus> videoConverterStatusProperty() { DoubleProperty setupProgressProperty(final ToolType type) {
return videoConverterStatus; return this.setupProgresses.get(type);
} }
@Override @Override
public double videoConverterSetupProgress() { public String setupProgressLabel(final ToolType type) {
return videoConverterSetupProgress.get(); return this.setupProgressLabels.get(type).get();
} }
@Override @Override
public void setVideoConverterSetupProgress(final double progress) { public void setSetupProgressLabel(final ToolType type, final String label) {
videoConverterSetupProgress.set(progress); this.setupProgressLabels.get(type).set(label);
} }
DoubleProperty videoConverterSetupProgressProperty() { StringProperty setupProgressLabelProperty(final ToolType type) {
return videoConverterSetupProgress; return this.setupProgressLabels.get(type);
} }
@Override @Override
public String videoConverterSetupProgressLabel() { public boolean isSetupInProgress(final ToolType type) {
return videoConverterSetupProgressLabel.get(); return this.setupInProgress.get(type).get();
} }
@Override ReadOnlyBooleanProperty setupInProgressProperty(final ToolType type) {
public void setVideoConverterSetupProgressLabel(final String label) { return this.setupInProgress.get(type).getReadOnlyProperty();
videoConverterSetupProgressLabel.set(label);
} }
StringProperty videoConverterSetupProgressLabelProperty() { private static <T> ObservableList<T> getUnmodifiableObservableList(final Collection<? extends T> collection) {
return videoConverterSetupProgressLabel; return FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(collection));
}
@Override
public SetupStatus translatorStatus() {
return translatorStatus.get();
}
@Override
public void setTranslatorStatus(final SetupStatus status) {
translatorStatus.set(status);
}
ObjectProperty<SetupStatus> translatorStatusProperty() {
return translatorStatus;
}
@Override
public double translatorSetupProgress() {
return translatorSetupProgress.get();
}
@Override
public void setTranslatorSetupProgress(final double progress) {
translatorSetupProgress.set(progress);
}
DoubleProperty translatorSetupProgressProperty() {
return translatorSetupProgress;
}
@Override
public String translatorSetupProgressLabel() {
return translatorSetupProgressLabel.get();
}
@Override
public void setTranslatorSetupProgressLabel(final String label) {
translatorSetupProgressLabel.set(label);
}
StringProperty translatorSetupProgressLabelProperty() {
return translatorSetupProgressLabel;
} }
} }

View File

@@ -0,0 +1,16 @@
package com.github.gtache.autosubtitle.gui.setup.fx;
import com.github.gtache.autosubtitle.setup.SetupManager;
import javafx.util.StringConverter;
class SetupManagerStringConverter extends StringConverter<SetupManager> {
@Override
public String toString(final SetupManager object) {
return object.name();
}
@Override
public SetupManager fromString(final String string) {
return null;
}
}

View File

@@ -1,8 +1,10 @@
package com.github.gtache.autosubtitle.gui.subtitles.fx; package com.github.gtache.autosubtitle.gui.subtitles.fx;
import com.github.gtache.autosubtitle.Language; import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.gui.fx.FXBinder; import com.github.gtache.autosubtitle.gui.fx.FXBinder;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel; import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.setup.fx.FXSetupModel;
import com.github.gtache.autosubtitle.gui.work.WorkStatus; import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel; import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel;
import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl; import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
@@ -14,7 +16,8 @@ import javafx.beans.binding.Bindings;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Objects;
import static java.util.Objects.requireNonNull;
/** /**
* Binds the subtitles model * Binds the subtitles model
@@ -24,13 +27,15 @@ public class FXSubtitlesBinder implements FXBinder {
private final FXWorkModel workModel; private final FXWorkModel workModel;
private final FXParametersModel parametersModel; private final FXParametersModel parametersModel;
private final FXSetupModel setupModel;
private final FXSubtitlesModel subtitlesModel; private final FXSubtitlesModel subtitlesModel;
@Inject @Inject
FXSubtitlesBinder(final FXWorkModel workModel, final FXParametersModel parametersModel, final FXSubtitlesModel subtitlesModel) { FXSubtitlesBinder(final FXWorkModel workModel, final FXParametersModel parametersModel, final FXSetupModel setupModel, final FXSubtitlesModel subtitlesModel) {
this.workModel = Objects.requireNonNull(workModel); this.workModel = requireNonNull(workModel);
this.parametersModel = Objects.requireNonNull(parametersModel); this.parametersModel = requireNonNull(parametersModel);
this.subtitlesModel = Objects.requireNonNull(subtitlesModel); this.setupModel = requireNonNull(setupModel);
this.subtitlesModel = requireNonNull(subtitlesModel);
} }
@Override @Override
@@ -74,5 +79,12 @@ public class FXSubtitlesBinder implements FXBinder {
final var parseOptions = new ParseOptionsImpl(parametersModel.maxLineLength(), parametersModel.maxLines(), parametersModel.font()); final var parseOptions = new ParseOptionsImpl(parametersModel.maxLineLength(), parametersModel.maxLines(), parametersModel.font());
return new ImportOptionsImpl(parseOptions); return new ImportOptionsImpl(parseOptions);
}, parametersModel.maxLineLengthProperty(), parametersModel.maxLinesProperty(), parametersModel.fontProperty())); }, parametersModel.maxLineLengthProperty(), parametersModel.maxLinesProperty(), parametersModel.fontProperty()));
setupModel.selectedToolProperty(ToolType.TRANSLATOR).addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
subtitlesModel.translatorProperty().set(subtitlesModel.availableTranslators().get(newValue));
}
});
} }
} }

View File

@@ -10,7 +10,6 @@ import com.github.gtache.autosubtitle.subtitle.converter.ParseException;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import com.github.gtache.autosubtitle.translation.TranslationException; import com.github.gtache.autosubtitle.translation.TranslationException;
import com.github.gtache.autosubtitle.translation.Translator;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
@@ -87,21 +86,18 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
private TableColumn<ObservableSubtitleImpl, String> textColumn; private TableColumn<ObservableSubtitleImpl, String> textColumn;
private final FXSubtitlesModel model; private final FXSubtitlesModel model;
private final FXSubtitlesBinder binder;
private final SubtitleImporterExporter<?> importerExporter; private final SubtitleImporterExporter<?> importerExporter;
private final TimeFormatter timeFormatter; private final TimeFormatter timeFormatter;
private final List<String> subtitleExtensions; private final List<String> subtitleExtensions;
private final Translator<?> translator;
@Inject @Inject
FXSubtitlesController(final FXSubtitlesModel model, final FXSubtitlesBinder binder, final SubtitleImporterExporter importerExporter, final TimeFormatter timeFormatter, FXSubtitlesController(final FXSubtitlesModel model, final FXSubtitlesBinder binder,
final Translator translator) { final SubtitleImporterExporter importerExporter, final TimeFormatter timeFormatter) {
this.model = requireNonNull(model); this.model = requireNonNull(model);
this.binder = requireNonNull(binder);
this.importerExporter = requireNonNull(importerExporter); this.importerExporter = requireNonNull(importerExporter);
this.timeFormatter = requireNonNull(timeFormatter); this.timeFormatter = requireNonNull(timeFormatter);
this.subtitleExtensions = importerExporter.supportedSingleFileExtensions().stream().map(c -> "*." + c).sorted().toList(); this.subtitleExtensions = importerExporter.supportedSingleFileExtensions().stream().map(c -> "*." + c).sorted().toList();
this.translator = requireNonNull(translator); binder.createBindings();
} }
@FXML @FXML
@@ -135,7 +131,6 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
}); });
translationsCombobox.setOnAction(e -> translateToNewLanguage()); translationsCombobox.setOnAction(e -> translateToNewLanguage());
binder.createBindings();
} }
private void translateToNewLanguage() { private void translateToNewLanguage() {
@@ -149,10 +144,10 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
if (model.selectedCollection() == null) { if (model.selectedCollection() == null) {
return null; return null;
} else { } else {
return translator.translate(model.selectedCollection(), value); return model.translatorProperty().get().translate(model.selectedCollection(), value);
} }
} else { } else {
return translator.translate(mainCollection, value); return model.translatorProperty().get().translate(mainCollection, value);
} }
} catch (final TranslationException ex) { } catch (final TranslationException ex) {
throw new CompletionException(ex); throw new CompletionException(ex);

View File

@@ -6,6 +6,7 @@ import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.ImportOptions; import com.github.gtache.autosubtitle.subtitle.ImportOptions;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import com.github.gtache.autosubtitle.translation.Translator;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
@@ -22,6 +23,7 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.Map;
/** /**
* FX implementation of {@link SubtitlesModel} * FX implementation of {@link SubtitlesModel}
@@ -39,6 +41,8 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
private final ObjectProperty<ObservableSubtitleCollectionImpl> selectedCollection; private final ObjectProperty<ObservableSubtitleCollectionImpl> selectedCollection;
private final ObservableList<ObservableSubtitleImpl> selectedSubtitles; private final ObservableList<ObservableSubtitleImpl> selectedSubtitles;
private final ObjectProperty<ObservableSubtitleImpl> selectedSubtitle; private final ObjectProperty<ObservableSubtitleImpl> selectedSubtitle;
private final ObservableMap<String, Translator<?>> availableTranslators;
private final ObjectProperty<Translator<?>> translator;
private final BooleanProperty canLoadSubtitles; private final BooleanProperty canLoadSubtitles;
private final BooleanProperty canAddSubtitle; private final BooleanProperty canAddSubtitle;
@@ -50,7 +54,8 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
private final ObjectProperty<ImportOptions> importOptions; private final ObjectProperty<ImportOptions> importOptions;
@Inject @Inject
FXSubtitlesModel() { FXSubtitlesModel(final Map<String, Translator<?>> translators, final Translator defaultTranslator) {
this.availableTranslators = FXCollections.unmodifiableObservableMap(FXCollections.observableMap(translators));
this.availableVideoLanguages = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(Arrays.stream(Language.values()) this.availableVideoLanguages = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(Arrays.stream(Language.values())
.sorted((o1, o2) -> { .sorted((o1, o2) -> {
if (o1 == Language.AUTO) { if (o1 == Language.AUTO) {
@@ -78,6 +83,7 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
this.isTranslating = new SimpleBooleanProperty(false); this.isTranslating = new SimpleBooleanProperty(false);
this.exportOptions = new SimpleObjectProperty<>(); this.exportOptions = new SimpleObjectProperty<>();
this.importOptions = new SimpleObjectProperty<>(); this.importOptions = new SimpleObjectProperty<>();
this.translator = new SimpleObjectProperty<>(defaultTranslator);
canSaveSubtitles.bind(Bindings.isNotEmpty(collections)); canSaveSubtitles.bind(Bindings.isNotEmpty(collections));
collections.addListener((MapChangeListener<Language, ObservableSubtitleCollectionImpl>) change -> collections.addListener((MapChangeListener<Language, ObservableSubtitleCollectionImpl>) change ->
@@ -275,4 +281,12 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
public ObjectProperty<ImportOptions> importOptionsProperty() { public ObjectProperty<ImportOptions> importOptionsProperty() {
return importOptions; return importOptions;
} }
public ObservableMap<String, Translator<?>> availableTranslators() {
return availableTranslators;
}
public ObjectProperty<Translator<?>> translatorProperty() {
return translator;
}
} }

View File

@@ -1,7 +1,5 @@
package com.github.gtache.autosubtitle.gui.work.fx; package com.github.gtache.autosubtitle.gui.work.fx;
import com.github.gtache.autosubtitle.VideoConverter;
import com.github.gtache.autosubtitle.VideoLoader;
import com.github.gtache.autosubtitle.gui.fx.AbstractFXController; import com.github.gtache.autosubtitle.gui.fx.AbstractFXController;
import com.github.gtache.autosubtitle.gui.media.fx.FXMediaController; import com.github.gtache.autosubtitle.gui.media.fx.FXMediaController;
import com.github.gtache.autosubtitle.gui.work.WorkController; import com.github.gtache.autosubtitle.gui.work.WorkController;
@@ -9,7 +7,6 @@ import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection; import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractException; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractException;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener; import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
@@ -52,18 +49,14 @@ public class FXWorkController extends AbstractFXController implements WorkContro
@FXML @FXML
private TextField fileField; private TextField fileField;
@FXML @FXML
private Button extractButton; private Button extractButton;
@FXML @FXML
private Button exportSoftButton; private Button exportSoftButton;
@FXML @FXML
private Button exportHardButton; private Button exportHardButton;
@FXML @FXML
private FXMediaController mediaController; private FXMediaController mediaController;
@FXML @FXML
private Label progressLabel; private Label progressLabel;
@FXML @FXML
@@ -74,19 +67,11 @@ public class FXWorkController extends AbstractFXController implements WorkContro
private ResourceBundle resources; private ResourceBundle resources;
private final FXWorkModel model; private final FXWorkModel model;
private final FXWorkBinder binder;
private final SubtitleExtractor<?> subtitleExtractor;
private final VideoConverter videoConverter;
private final VideoLoader videoLoader;
@Inject @Inject
FXWorkController(final FXWorkModel model, final FXWorkBinder binder, final SubtitleExtractor subtitleExtractor, FXWorkController(final FXWorkModel model, final FXWorkBinder binder) {
final VideoLoader videoLoader, final VideoConverter videoConverter) {
this.model = requireNonNull(model); this.model = requireNonNull(model);
this.binder = requireNonNull(binder); binder.createBindings();
this.subtitleExtractor = requireNonNull(subtitleExtractor);
this.videoConverter = requireNonNull(videoConverter);
this.videoLoader = requireNonNull(videoLoader);
} }
@FXML @FXML
@@ -103,9 +88,11 @@ public class FXWorkController extends AbstractFXController implements WorkContro
} }
}); });
binder.createBindings(); model.subtitleExtractorProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
subtitleExtractor.addListener(this); newValue.addListener(FXWorkController.this);
}
});
} }
private void bindProgress() { private void bindProgress() {
@@ -142,7 +129,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
private SubtitleCollection<?> extractAsync() { private SubtitleCollection<?> extractAsync() {
try { try {
return subtitleExtractor.extract(model.video(), model.extractOptions()); return model.subtitleExtractorProperty().get().extract(model.video(), model.extractOptions());
} catch (final ExtractException e) { } catch (final ExtractException e) {
throw new CompletionException(e); throw new CompletionException(e);
} }
@@ -161,7 +148,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
@Override @Override
public void loadVideo(final Path file) { public void loadVideo(final Path file) {
try { try {
final var loadedVideo = videoLoader.loadVideo(file); final var loadedVideo = model.videoLoaderProperty().get().loadVideo(file);
fileField.setText(file.toAbsolutePath().toString()); fileField.setText(file.toAbsolutePath().toString());
model.videoProperty().set(loadedVideo); model.videoProperty().set(loadedVideo);
} catch (final IOException e) { } catch (final IOException e) {
@@ -182,7 +169,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
model.setStatus(WorkStatus.EXPORTING); model.setStatus(WorkStatus.EXPORTING);
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
videoConverter.addSoftSubtitles(model.video(), model.collections().values(), model.exportOptions(), file.toPath()); model.videoConverterProperty().get().addSoftSubtitles(model.video(), model.collections().values(), model.exportOptions(), file.toPath());
} catch (final IOException e) { } catch (final IOException e) {
throw new CompletionException(e); throw new CompletionException(e);
} }
@@ -207,7 +194,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
model.setStatus(WorkStatus.EXPORTING); model.setStatus(WorkStatus.EXPORTING);
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
videoConverter.addHardSubtitles(model.video(), model.collections().get(model.extractOptions().language()), model.exportOptions(), file.toPath()); model.videoConverterProperty().get().addHardSubtitles(model.video(), model.collections().get(model.extractOptions().language()), model.exportOptions(), file.toPath());
} catch (final IOException e) { } catch (final IOException e) {
throw new CompletionException(e); throw new CompletionException(e);
} }

View File

@@ -2,12 +2,15 @@ package com.github.gtache.autosubtitle.gui.work.fx;
import com.github.gtache.autosubtitle.Language; import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video; import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoConverter;
import com.github.gtache.autosubtitle.VideoLoader;
import com.github.gtache.autosubtitle.gui.work.WorkModel; import com.github.gtache.autosubtitle.gui.work.WorkModel;
import com.github.gtache.autosubtitle.gui.work.WorkStatus; import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.subtitle.EditableSubtitle; import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
import com.github.gtache.autosubtitle.subtitle.ExportOptions; import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection; import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
@@ -24,6 +27,7 @@ import javafx.collections.ObservableMap;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Map;
/** /**
* FX implementation of {@link WorkModel} * FX implementation of {@link WorkModel}
@@ -31,6 +35,12 @@ import javax.inject.Singleton;
@Singleton @Singleton
public class FXWorkModel implements WorkModel { public class FXWorkModel implements WorkModel {
private final ObservableMap<String, SubtitleExtractor<?>> availableSubtitleExtractors;
private final ObjectProperty<SubtitleExtractor<?>> subtitleExtractor;
private final ObservableMap<String, VideoLoader> availableVideoLoaders;
private final ObjectProperty<VideoLoader> videoLoader;
private final ObservableMap<String, VideoConverter> availableVideoConverters;
private final ObjectProperty<VideoConverter> videoConverter;
private final ObjectProperty<Video> video; private final ObjectProperty<Video> video;
private final ObjectProperty<WorkStatus> workStatus; private final ObjectProperty<WorkStatus> workStatus;
private final DoubleProperty progress; private final DoubleProperty progress;
@@ -46,7 +56,15 @@ public class FXWorkModel implements WorkModel {
private final ObjectProperty<ExtractOptions> extractOptions; private final ObjectProperty<ExtractOptions> extractOptions;
@Inject @Inject
FXWorkModel() { FXWorkModel(final Map<String, SubtitleExtractor<?>> subtitleExtractors, final SubtitleExtractor defaultExtractor,
final Map<String, VideoLoader> videoLoaders, final VideoLoader defaultVideoLoader,
final Map<String, VideoConverter> videoConverters, final VideoConverter defaultVideoConverter) {
this.availableSubtitleExtractors = FXCollections.unmodifiableObservableMap(FXCollections.observableMap(subtitleExtractors));
this.subtitleExtractor = new SimpleObjectProperty<>(defaultExtractor);
this.availableVideoLoaders = FXCollections.unmodifiableObservableMap(FXCollections.observableMap(videoLoaders));
this.videoLoader = new SimpleObjectProperty<>(defaultVideoLoader);
this.availableVideoConverters = FXCollections.unmodifiableObservableMap(FXCollections.observableMap(videoConverters));
this.videoConverter = new SimpleObjectProperty<>(defaultVideoConverter);
this.video = new SimpleObjectProperty<>(); this.video = new SimpleObjectProperty<>();
this.workStatus = new SimpleObjectProperty<>(WorkStatus.IDLE); this.workStatus = new SimpleObjectProperty<>(WorkStatus.IDLE);
this.progress = new SimpleDoubleProperty(-1); this.progress = new SimpleDoubleProperty(-1);
@@ -175,7 +193,7 @@ public class FXWorkModel implements WorkModel {
exportOptions.set(options); exportOptions.set(options);
} }
public ObjectProperty<ExportOptions> exportOptionsProperty() { ObjectProperty<ExportOptions> exportOptionsProperty() {
return exportOptions; return exportOptions;
} }
@@ -189,7 +207,31 @@ public class FXWorkModel implements WorkModel {
extractOptions.set(options); extractOptions.set(options);
} }
public ObjectProperty<ExtractOptions> extractOptionsProperty() { ObjectProperty<ExtractOptions> extractOptionsProperty() {
return extractOptions; return extractOptions;
} }
ObservableMap<String, SubtitleExtractor<?>> availableSubtitleExtractors() {
return availableSubtitleExtractors;
}
ObjectProperty<SubtitleExtractor<?>> subtitleExtractorProperty() {
return subtitleExtractor;
}
ObservableMap<String, VideoLoader> availableVideoLoaders() {
return availableVideoLoaders;
}
ObjectProperty<VideoLoader> videoLoaderProperty() {
return videoLoader;
}
ObservableMap<String, VideoConverter> availableVideoConverters() {
return availableVideoConverters;
}
ObjectProperty<VideoConverter> videoConverterProperty() {
return videoConverter;
}
} }

View File

@@ -2,13 +2,11 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<GridPane fx:id="setupGrid" hgap="10.0" vgap="10.0" xmlns="http://javafx.com/javafx/22"
<GridPane hgap="10.0" vgap="10.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.github.gtache.autosubtitle.gui.setup.fx.FXSetupController"> fx:controller="com.github.gtache.autosubtitle.gui.setup.fx.FXSetupController">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES"/> <ColumnConstraints hgrow="SOMETIMES"/>
@@ -18,35 +16,11 @@
<ColumnConstraints hgrow="SOMETIMES"/> <ColumnConstraints hgrow="SOMETIMES"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/> <RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/> <RowConstraints vgrow="ALWAYS"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="converterNameLabel" text="Label" GridPane.rowIndex="1"/>
<Label fx:id="converterStatusLabel" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label fx:id="extractorNameLabel" text="Label" GridPane.rowIndex="2"/>
<Label fx:id="extractorStatusLabel" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label fx:id="translatorNameLabel" text="Label" GridPane.rowIndex="3"/>
<Label fx:id="translatorStatusLabel" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
<MenuButton fx:id="converterButton" mnemonicParsing="false" text="%setup.menu.label" GridPane.columnIndex="2"
GridPane.rowIndex="1"/>
<MenuButton fx:id="extractorButton" mnemonicParsing="false" text="%setup.menu.label" GridPane.columnIndex="2"
GridPane.rowIndex="2"/>
<MenuButton fx:id="translatorButton" mnemonicParsing="false" text="%setup.menu.label" GridPane.columnIndex="2"
GridPane.rowIndex="3"/>
<Label text="%setup.description.label" GridPane.columnSpan="2147483647"/> <Label text="%setup.description.label" GridPane.columnSpan="2147483647"/>
<ProgressBar fx:id="converterProgress" prefWidth="200.0" progress="0.0" GridPane.columnIndex="3"
GridPane.rowIndex="1"/>
<ProgressBar fx:id="extractorProgress" prefWidth="200.0" progress="0.0" GridPane.columnIndex="3"
GridPane.rowIndex="2"/>
<ProgressBar fx:id="translatorProgress" prefWidth="200.0" progress="0.0" GridPane.columnIndex="3"
GridPane.rowIndex="3"/>
<Label fx:id="converterProgressLabel" text="Label" GridPane.columnIndex="4" GridPane.rowIndex="1"/>
<Label fx:id="extractorProgressLabel" text="Label" GridPane.columnIndex="4" GridPane.rowIndex="2"/>
<Label fx:id="translatorProgressLabel" text="Label" GridPane.columnIndex="4" GridPane.rowIndex="3"/>
</children> </children>
<padding> <padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>

View File

@@ -52,7 +52,7 @@ class TestFXParametersController extends FxRobot {
this.videoConverter = requireNonNull(videoConverter); this.videoConverter = requireNonNull(videoConverter);
this.translator = requireNonNull(translator); this.translator = requireNonNull(translator);
this.timeFormatter = requireNonNull(timeFormatter); this.timeFormatter = requireNonNull(timeFormatter);
this.model = spy(new FXParametersModel(mock(ExtractionModelProvider.class), "Arial", 12, 40, 1)); this.model = spy(new FXParametersModel(Map.of(), mock(ExtractionModelProvider.class), "Arial", 12, 40, 1));
this.binder = requireNonNull(binder); this.binder = requireNonNull(binder);
this.window = FxToolkit.registerPrimaryStage(); this.window = FxToolkit.registerPrimaryStage();
this.controller = spy(FXParametersController.class); this.controller = spy(FXParametersController.class);

View File

@@ -11,6 +11,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -42,7 +43,7 @@ class TestFXParametersModel {
void beforeEach() { void beforeEach() {
when(provider.getDefaultExtractionModel()).thenReturn(defaultExtractionModel); when(provider.getDefaultExtractionModel()).thenReturn(defaultExtractionModel);
when(provider.getAvailableExtractionModels()).thenReturn(availableExtractionModels); when(provider.getAvailableExtractionModels()).thenReturn(availableExtractionModels);
this.model = new FXParametersModel(provider, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_MAX_LINE_LENGTH, DEFAULT_MAX_LINES); this.model = new FXParametersModel(Map.of(), provider, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_MAX_LINE_LENGTH, DEFAULT_MAX_LINES); //TODO
} }
@Test @Test

View File

@@ -33,16 +33,16 @@ class TestFXSetupController extends FxRobot {
private final FXSetupModel model; private final FXSetupModel model;
private final FXSetupController controller; private final FXSetupController controller;
private final FXWorkBinder binder; private final FXWorkBinder binder;
private final SubtitleExtractor extractor; private final SubtitleExtractor<?> extractor;
private final Map<String, SubtitleConverter> subtitleConverters; private final Map<String, SubtitleConverter> subtitleConverters;
private final VideoLoader videoLoader; private final VideoLoader videoLoader;
private final VideoConverter videoConverter; private final VideoConverter videoConverter;
private final Translator translator; private final Translator<?> translator;
private final TimeFormatter timeFormatter; private final TimeFormatter timeFormatter;
private final Stage window; private final Stage window;
TestFXSetupController(@Mock final SubtitleExtractor extractor, @Mock final SubtitleConverter subtitleConverter, @Mock final VideoLoader videoLoader, TestFXSetupController(@Mock final SubtitleExtractor<?> extractor, @Mock final SubtitleConverter<?> subtitleConverter, @Mock final VideoLoader videoLoader,
@Mock final VideoConverter videoConverter, @Mock final Translator translator, @Mock final TimeFormatter timeFormatter, @Mock final VideoConverter videoConverter, @Mock final Translator<?> translator, @Mock final TimeFormatter timeFormatter,
@Mock final FXWorkBinder binder) throws TimeoutException { @Mock final FXWorkBinder binder) throws TimeoutException {
this.extractor = requireNonNull(extractor); this.extractor = requireNonNull(extractor);
this.subtitleConverters = Map.of("srt", requireNonNull(subtitleConverter)); this.subtitleConverters = Map.of("srt", requireNonNull(subtitleConverter));
@@ -50,7 +50,7 @@ class TestFXSetupController extends FxRobot {
this.videoConverter = requireNonNull(videoConverter); this.videoConverter = requireNonNull(videoConverter);
this.translator = requireNonNull(translator); this.translator = requireNonNull(translator);
this.timeFormatter = requireNonNull(timeFormatter); this.timeFormatter = requireNonNull(timeFormatter);
this.model = spy(new FXSetupModel()); this.model = spy(new FXSetupModel(Map.of(), Map.of())); //TODO
this.binder = requireNonNull(binder); this.binder = requireNonNull(binder);
this.window = FxToolkit.registerPrimaryStage(); this.window = FxToolkit.registerPrimaryStage();
this.controller = spy(FXSetupController.class); this.controller = spy(FXSetupController.class);

View File

@@ -1,97 +1,12 @@
package com.github.gtache.autosubtitle.gui.setup.fx; package com.github.gtache.autosubtitle.gui.setup.fx;
import com.github.gtache.autosubtitle.setup.SetupStatus; import java.util.Map;
import org.junit.jupiter.api.Test;
import static com.github.gtache.autosubtitle.setup.SetupStatus.ERRORED;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestFXSetupModel { class TestFXSetupModel {
private final FXSetupModel model; private final FXSetupModel model;
TestFXSetupModel() { TestFXSetupModel() {
this.model = new FXSetupModel(); this.model = new FXSetupModel(Map.of(), Map.of()); //TODO
}
@Test
void testSubtitleExtractorStatus() {
assertEquals(ERRORED, model.subtitleExtractorStatus());
assertEquals(ERRORED, model.subtitleExtractorStatusProperty().get());
model.setSubtitleExtractorStatus(SetupStatus.SYSTEM_INSTALLED);
assertEquals(SetupStatus.SYSTEM_INSTALLED, model.subtitleExtractorStatus());
assertEquals(SetupStatus.SYSTEM_INSTALLED, model.subtitleExtractorStatusProperty().get());
}
@Test
void testSubtitleExtractorSetupProgress() {
assertEquals(-2, model.subtitleExtractorSetupProgress());
assertEquals(-2, model.subtitleExtractorSetupProgressProperty().get());
model.setSubtitleExtractorSetupProgress(0.5);
assertEquals(0.5, model.subtitleExtractorSetupProgress());
assertEquals(0.5, model.subtitleExtractorSetupProgressProperty().get());
}
@Test
void testSubtitleExtractorSetupProgressLabel() {
assertEquals("", model.subtitleExtractorSetupProgressLabel());
assertEquals("", model.subtitleExtractorSetupProgressLabelProperty().get());
model.setSubtitleExtractorSetupProgressLabel("test");
assertEquals("test", model.subtitleExtractorSetupProgressLabel());
assertEquals("test", model.subtitleExtractorSetupProgressLabelProperty().get());
}
@Test
void testVideoConverterStatus() {
assertEquals(ERRORED, model.videoConverterStatus());
assertEquals(ERRORED, model.videoConverterStatusProperty().get());
model.setVideoConverterStatus(SetupStatus.SYSTEM_INSTALLED);
assertEquals(SetupStatus.SYSTEM_INSTALLED, model.videoConverterStatus());
assertEquals(SetupStatus.SYSTEM_INSTALLED, model.videoConverterStatusProperty().get());
}
@Test
void testVideoConverterSetupProgress() {
assertEquals(-2, model.videoConverterSetupProgress());
assertEquals(-2, model.videoConverterSetupProgressProperty().get());
model.setVideoConverterSetupProgress(0.5);
assertEquals(0.5, model.videoConverterSetupProgress());
assertEquals(0.5, model.videoConverterSetupProgressProperty().get());
}
@Test
void testVideoConverterSetupProgressLabel() {
assertEquals("", model.videoConverterSetupProgressLabel());
assertEquals("", model.videoConverterSetupProgressLabelProperty().get());
model.setVideoConverterSetupProgressLabel("test");
assertEquals("test", model.videoConverterSetupProgressLabel());
assertEquals("test", model.videoConverterSetupProgressLabelProperty().get());
}
@Test
void testTranslatorStatus() {
assertEquals(ERRORED, model.translatorStatus());
assertEquals(ERRORED, model.translatorStatusProperty().get());
model.setTranslatorStatus(SetupStatus.SYSTEM_INSTALLED);
assertEquals(SetupStatus.SYSTEM_INSTALLED, model.translatorStatus());
assertEquals(SetupStatus.SYSTEM_INSTALLED, model.translatorStatusProperty().get());
}
@Test
void testTranslatorSetupProgress() {
assertEquals(-2, model.translatorSetupProgress());
assertEquals(-2, model.translatorSetupProgressProperty().get());
model.setTranslatorSetupProgress(0.5);
assertEquals(0.5, model.translatorSetupProgress());
assertEquals(0.5, model.translatorSetupProgressProperty().get());
}
@Test
void testTranslatorSetupProgressLabel() {
assertEquals("", model.translatorSetupProgressLabel());
assertEquals("", model.translatorSetupProgressLabelProperty().get());
model.setTranslatorSetupProgressLabel("test");
assertEquals("test", model.translatorSetupProgressLabel());
assertEquals("test", model.translatorSetupProgressLabelProperty().get());
} }
} }

View File

@@ -1,11 +1,14 @@
package com.github.gtache.autosubtitle.gui.subtitles.fx; package com.github.gtache.autosubtitle.gui.subtitles.fx;
import com.github.gtache.autosubtitle.Language; import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.Video; import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoInfo; import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel; import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.setup.fx.FXSetupModel;
import com.github.gtache.autosubtitle.gui.work.WorkStatus; import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel; import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel;
import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.subtitle.OutputFormat; import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl; import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl; import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl;
@@ -15,6 +18,7 @@ import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl; import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.FontImpl; import com.github.gtache.autosubtitle.subtitle.impl.FontImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ImportOptionsImpl; import com.github.gtache.autosubtitle.subtitle.impl.ImportOptionsImpl;
import com.github.gtache.autosubtitle.translation.Translator;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@@ -26,6 +30,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@@ -35,6 +40,14 @@ class TestFXSubtitlesBinder {
private final FXWorkModel workModel; private final FXWorkModel workModel;
private final FXSubtitlesModel subtitlesModel; private final FXSubtitlesModel subtitlesModel;
private final Map<ToolType, Map<String, SetupManager>> setupManagers;
private final Map<ToolType, SetupManager> defaultManagers;
private final Map<String, Translator<?>> translators;
private final SetupManager firstManager;
private final SetupManager secondManager;
private final Translator<?> firstTranslator;
private final Translator<?> secondTranslator;
private final FXSetupModel setupModel;
private final FXParametersModel parametersModel; private final FXParametersModel parametersModel;
private final FXSubtitlesBinder binder; private final FXSubtitlesBinder binder;
private final String defaultFontFamily; private final String defaultFontFamily;
@@ -42,7 +55,9 @@ class TestFXSubtitlesBinder {
private final int defaultMaxLineLength; private final int defaultMaxLineLength;
private final int defaultMaxLines; private final int defaultMaxLines;
TestFXSubtitlesBinder(@Mock final ExtractionModelProvider extractionModelProvider) { TestFXSubtitlesBinder(@Mock final ExtractionModelProvider extractionModelProvider, @Mock final SetupManager firstManager,
@Mock final SetupManager secondManager, @Mock final Translator<?> firstTranslator,
@Mock final Translator<?> secondTranslator) {
this.workModel = spy(FXWorkModel.class); this.workModel = spy(FXWorkModel.class);
this.defaultFontFamily = "Arial"; this.defaultFontFamily = "Arial";
this.defaultFontSize = 12; this.defaultFontSize = 12;
@@ -50,8 +65,16 @@ class TestFXSubtitlesBinder {
this.defaultMaxLines = 2; this.defaultMaxLines = 2;
this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS) this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS)
.useConstructor(extractionModelProvider, defaultFontFamily, defaultFontSize, defaultMaxLineLength, defaultMaxLines)); .useConstructor(extractionModelProvider, defaultFontFamily, defaultFontSize, defaultMaxLineLength, defaultMaxLines));
this.subtitlesModel = new FXSubtitlesModel(); this.firstManager = Objects.requireNonNull(firstManager);
this.binder = new FXSubtitlesBinder(workModel, parametersModel, subtitlesModel); this.secondManager = Objects.requireNonNull(secondManager);
this.firstTranslator = Objects.requireNonNull(firstTranslator);
this.secondTranslator = Objects.requireNonNull(secondTranslator);
this.translators = Map.of("first", firstTranslator, "second", secondTranslator);
this.defaultManagers = Map.of(ToolType.TRANSLATOR, firstManager);
this.setupManagers = Map.of(ToolType.TRANSLATOR, Map.of("first", firstManager, "second", secondManager));
this.setupModel = mock(FXSetupModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS).useConstructor(setupManagers, defaultManagers));
this.subtitlesModel = new FXSubtitlesModel(translators, firstTranslator);
this.binder = new FXSubtitlesBinder(workModel, parametersModel, setupModel, subtitlesModel);
} }
@BeforeEach @BeforeEach
@@ -180,4 +203,13 @@ class TestFXSubtitlesBinder {
parametersModel.setMaxLines(4); parametersModel.setMaxLines(4);
assertEquals(new ImportOptionsImpl(new ParseOptionsImpl(1, 4, new FontImpl("TT", 14))), subtitlesModel.importOptions()); assertEquals(new ImportOptionsImpl(new ParseOptionsImpl(1, 4, new FontImpl("TT", 14))), subtitlesModel.importOptions());
} }
@Test
void testTranslatorsBinding() {
assertEquals(firstTranslator, subtitlesModel.translatorProperty().get());
setupModel.setSelectedSetupManager(ToolType.TRANSLATOR, secondManager);
assertEquals(secondTranslator, subtitlesModel.translatorProperty().get());
setupModel.setSelectedSetupManager(ToolType.TRANSLATOR, null);
assertEquals(secondTranslator, subtitlesModel.translatorProperty().get());
}
} }

View File

@@ -52,7 +52,7 @@ class TestFXSubtitlesController extends FxRobot {
this.videoConverter = requireNonNull(videoConverter); this.videoConverter = requireNonNull(videoConverter);
this.translator = requireNonNull(translator); this.translator = requireNonNull(translator);
this.timeFormatter = requireNonNull(timeFormatter); this.timeFormatter = requireNonNull(timeFormatter);
this.model = spy(new FXSubtitlesModel()); this.model = spy(new FXSubtitlesModel(Map.of(), translator));
this.binder = requireNonNull(binder); this.binder = requireNonNull(binder);
this.window = FxToolkit.registerPrimaryStage(); this.window = FxToolkit.registerPrimaryStage();
this.controller = spy(FXSubtitlesController.class); this.controller = spy(FXSubtitlesController.class);

View File

@@ -5,24 +5,36 @@ import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.ImportOptions; import com.github.gtache.autosubtitle.subtitle.ImportOptions;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import com.github.gtache.autosubtitle.translation.Translator;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestFXSubtitlesModel { class TestFXSubtitlesModel {
private final FXSubtitlesModel model; private final FXSubtitlesModel model;
private final Map<String, Translator<?>> translators;
private final Translator<?> translator1;
private final Translator<?> translator2;
TestFXSubtitlesModel() { TestFXSubtitlesModel(@Mock final Translator<?> translator1, @Mock final Translator<?> translator2) {
this.model = new FXSubtitlesModel(); this.translator1 = requireNonNull(translator1);
this.translator2 = requireNonNull(translator2);
this.translators = Map.of("1", translator1, "2", translator2);
this.model = new FXSubtitlesModel(translators, translator1);
} }
@Test @Test
@@ -202,4 +214,16 @@ class TestFXSubtitlesModel {
final var options = mock(ImportOptions.class); final var options = mock(ImportOptions.class);
assertDoesNotThrow(() -> model.importOptionsProperty().set(options)); assertDoesNotThrow(() -> model.importOptionsProperty().set(options));
} }
@Test
void testAvailableTranslators() {
assertEquals(translators, model.availableTranslators());
assertThrows(UnsupportedOperationException.class, () -> model.availableTranslators().clear());
}
@Test
void testSelectedTranslator() {
assertEquals(translator1, model.translatorProperty().get());
assertDoesNotThrow(() -> model.translatorProperty().set(translator2));
}
} }

View File

@@ -2,7 +2,9 @@ package com.github.gtache.autosubtitle.gui.work.fx;
import com.github.gtache.autosubtitle.Language; import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video; import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoConverter;
import com.github.gtache.autosubtitle.VideoInfo; import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.VideoLoader;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel; import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.subtitles.fx.FXSubtitlesModel; import com.github.gtache.autosubtitle.gui.subtitles.fx.FXSubtitlesModel;
import com.github.gtache.autosubtitle.subtitle.OutputFormat; import com.github.gtache.autosubtitle.subtitle.OutputFormat;
@@ -10,6 +12,7 @@ import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl; import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractOptionsImpl; import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl; import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.FontImpl; import com.github.gtache.autosubtitle.subtitle.impl.FontImpl;
@@ -19,6 +22,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -49,7 +53,7 @@ class TestFXWorkBinder {
this.defaultMaxLines = 1; this.defaultMaxLines = 1;
this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS).useConstructor(extractionModelProvider, defaultFontFamily, defaultFontSize, defaultMaxLineLength, defaultMaxLines)); this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS).useConstructor(extractionModelProvider, defaultFontFamily, defaultFontSize, defaultMaxLineLength, defaultMaxLines));
this.subtitlesModel = spy(FXSubtitlesModel.class); this.subtitlesModel = spy(FXSubtitlesModel.class);
this.workModel = new FXWorkModel(); this.workModel = new FXWorkModel(Map.of(), mock(SubtitleExtractor.class), Map.of(), mock(VideoLoader.class), Map.of(), mock(VideoConverter.class)); //TODO
this.binder = new FXWorkBinder(workModel, parametersModel, subtitlesModel); this.binder = new FXWorkBinder(workModel, parametersModel, subtitlesModel);
} }

View File

@@ -18,6 +18,7 @@ import org.testfx.util.WaitForAsyncUtils;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -41,10 +42,10 @@ class TestFXWorkController extends FxRobot {
this.extractor = requireNonNull(extractor); this.extractor = requireNonNull(extractor);
this.videoLoader = requireNonNull(videoLoader); this.videoLoader = requireNonNull(videoLoader);
this.videoConverter = requireNonNull(videoConverter); this.videoConverter = requireNonNull(videoConverter);
this.model = spy(new FXWorkModel()); this.model = spy(new FXWorkModel(Map.of(), extractor, Map.of(), videoLoader, Map.of(), videoConverter));
this.binder = requireNonNull(binder); this.binder = requireNonNull(binder);
this.window = FxToolkit.registerPrimaryStage(); this.window = FxToolkit.registerPrimaryStage();
this.controller = spy(new FXWorkController(model, binder, extractor, videoLoader, videoConverter)); this.controller = spy(new FXWorkController(model, binder));
FxToolkit.setupStage(w -> { FxToolkit.setupStage(w -> {
final var loader = new FXMLLoader(getClass().getResource("/com/github/gtache/autosubtitle/gui/fx/workView.fxml")); final var loader = new FXMLLoader(getClass().getResource("/com/github/gtache/autosubtitle/gui/fx/workView.fxml"));

View File

@@ -2,11 +2,14 @@ package com.github.gtache.autosubtitle.gui.work.fx;
import com.github.gtache.autosubtitle.Language; import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video; import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoConverter;
import com.github.gtache.autosubtitle.VideoLoader;
import com.github.gtache.autosubtitle.gui.work.WorkStatus; import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.subtitle.EditableSubtitle; import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
import com.github.gtache.autosubtitle.subtitle.ExportOptions; import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection; import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl; import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -22,7 +25,7 @@ class TestFXWorkModel {
private final FXWorkModel model; private final FXWorkModel model;
TestFXWorkModel() { TestFXWorkModel() {
this.model = new FXWorkModel(); this.model = new FXWorkModel(Map.of(), mock(SubtitleExtractor.class), Map.of(), mock(VideoLoader.class), Map.of(), mock(VideoConverter.class)); //TODO
} }
@Test @Test

View File

@@ -24,6 +24,10 @@
<groupId>com.github.gtache.autosubtitle</groupId> <groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-gui-fx</artifactId> <artifactId>autosubtitle-gui-fx</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-whisper-base</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.github.gtache.autosubtitle</groupId> <groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-whisperx</artifactId> <artifactId>autosubtitle-whisperx</artifactId>

View File

@@ -5,6 +5,7 @@ import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegModule;
import com.github.gtache.autosubtitle.modules.gui.fx.FXModule; import com.github.gtache.autosubtitle.modules.gui.fx.FXModule;
import com.github.gtache.autosubtitle.modules.gui.impl.GuiCoreModule; import com.github.gtache.autosubtitle.modules.gui.impl.GuiCoreModule;
import com.github.gtache.autosubtitle.modules.impl.CoreModule; import com.github.gtache.autosubtitle.modules.impl.CoreModule;
import com.github.gtache.autosubtitle.modules.whisper.base.WhisperModule;
import com.github.gtache.autosubtitle.modules.whisperx.WhisperXModule; import com.github.gtache.autosubtitle.modules.whisperx.WhisperXModule;
import dagger.Component; import dagger.Component;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
@@ -17,7 +18,7 @@ import javax.inject.Singleton;
@FunctionalInterface @FunctionalInterface
@Singleton @Singleton
@Component(modules = {CoreModule.class, GuiCoreModule.class, FXModule.class, FFmpegModule.class, @Component(modules = {CoreModule.class, GuiCoreModule.class, FXModule.class, FFmpegModule.class,
WhisperXModule.class, DeepLModule.class}) WhisperModule.class, WhisperXModule.class, DeepLModule.class})
public interface RunComponent { public interface RunComponent {
/** /**

View File

@@ -5,6 +5,7 @@ module com.github.gtache.autosubtitle.gui.run {
requires com.github.gtache.autosubtitle.deepl; requires com.github.gtache.autosubtitle.deepl;
requires com.github.gtache.autosubtitle.ffmpeg; requires com.github.gtache.autosubtitle.ffmpeg;
requires com.github.gtache.autosubtitle.gui.fx; requires com.github.gtache.autosubtitle.gui.fx;
requires com.github.gtache.autosubtitle.whisper.base;
requires com.github.gtache.autosubtitle.whisperx; requires com.github.gtache.autosubtitle.whisperx;
requires javafx.fxml; requires javafx.fxml;
requires javafx.graphics; requires javafx.graphics;

37
pom.xml
View File

@@ -26,12 +26,12 @@
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<commons.compress.version>1.27.0</commons.compress.version> <commons.compress.version>1.27.1</commons.compress.version>
<dagger.version>2.51.1</dagger.version> <dagger.version>2.52</dagger.version>
<jackson.version>2.17.2</jackson.version> <jackson.version>2.18.0</jackson.version>
<junit.version>5.10.3</junit.version> <junit.version>5.11.1</junit.version>
<log4j.version>2.23.1</log4j.version> <log4j.version>2.23.1</log4j.version>
<mockito.version>5.12.0</mockito.version> <mockito.version>5.14.0</mockito.version>
<picocli.version>4.7.6</picocli.version> <picocli.version>4.7.6</picocli.version>
<xz.version>1.10</xz.version> <xz.version>1.10</xz.version>
</properties> </properties>
@@ -88,6 +88,11 @@
<artifactId>autosubtitle-whisper</artifactId> <artifactId>autosubtitle-whisper</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-whisper-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.gtache.autosubtitle</groupId> <groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-whisperx</artifactId> <artifactId>autosubtitle-whisperx</artifactId>
@@ -238,9 +243,31 @@
<showWarnings>true</showWarnings> <showWarnings>true</showWarnings>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -javaagent:${org.mockito:mockito-core:jar}</argLine>
</configuration>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>

View File

@@ -15,9 +15,5 @@
<groupId>com.github.gtache.autosubtitle</groupId> <groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-whisper-common</artifactId> <artifactId>autosubtitle-whisper-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.modules.setup.whisper; package com.github.gtache.autosubtitle.modules.setup.whisper.base;
import javax.inject.Qualifier; import javax.inject.Qualifier;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
@@ -12,5 +12,5 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented @Documented
@Retention(RUNTIME) @Retention(RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD}) @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
public @interface PythonVersion { public @interface Whisper {
} }

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.modules.setup.whisper; package com.github.gtache.autosubtitle.modules.setup.whisper.base;
import javax.inject.Qualifier; import javax.inject.Qualifier;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;

View File

@@ -0,0 +1,16 @@
package com.github.gtache.autosubtitle.modules.setup.whisper.base;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
public @interface WhisperPythonVersion {
}

View File

@@ -1,30 +1,33 @@
package com.github.gtache.autosubtitle.modules.setup.whisper.base; package com.github.gtache.autosubtitle.modules.setup.whisper.base;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.modules.setup.conda.CondaSetupModule;
import com.github.gtache.autosubtitle.modules.setup.impl.SubtitleExtractorSetup; import com.github.gtache.autosubtitle.modules.setup.impl.SubtitleExtractorSetup;
import com.github.gtache.autosubtitle.modules.setup.impl.ToolsRoot; import com.github.gtache.autosubtitle.modules.setup.impl.ToolsRoot;
import com.github.gtache.autosubtitle.modules.setup.whisper.PythonVersion;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperBundledRoot;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperCommonSetupModule;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperVenvPath;
import com.github.gtache.autosubtitle.setup.SetupManager; import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration;
import com.github.gtache.autosubtitle.setup.whisper.base.WhisperSetupManager; import com.github.gtache.autosubtitle.setup.whisper.base.WhisperSetupManager;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import java.nio.file.Path; import java.nio.file.Path;
/** /**
* Setup module for Whisper * Setup module for Whisper
*/ */
@Module(includes = WhisperCommonSetupModule.class) @Module(includes = CondaSetupModule.class)
public abstract class WhisperSetupModule { public abstract class WhisperSetupModule {
@Binds @Binds
@SubtitleExtractorSetup @SubtitleExtractorSetup
@IntoMap
@StringKey("whisper")
abstract SetupManager bindsSubtitleExtractorSetupManager(final WhisperSetupManager manager); abstract SetupManager bindsSubtitleExtractorSetupManager(final WhisperSetupManager manager);
@Provides @Provides
@PythonVersion @WhisperPythonVersion
static String providesPythonVersion() { static String providesPythonVersion() {
return "3.9.19"; return "3.9.19";
} }
@@ -40,4 +43,13 @@ public abstract class WhisperSetupModule {
static Path providesWhisperVenvPath(@WhisperBundledRoot final Path root) { static Path providesWhisperVenvPath(@WhisperBundledRoot final Path root) {
return root.resolve("whisper-env"); return root.resolve("whisper-env");
} }
@Provides
@Whisper
static WhisperSetupConfiguration providesWhisperSetupConfiguration(@WhisperBundledRoot final Path root,
@WhisperVenvPath final Path venvPath,
@WhisperPythonVersion final String pythonVersion,
final OS os) {
return new WhisperSetupConfiguration(root, venvPath, pythonVersion, os);
}
} }

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.modules.setup.whisper; package com.github.gtache.autosubtitle.modules.setup.whisper.base;
import javax.inject.Qualifier; import javax.inject.Qualifier;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;

View File

@@ -4,6 +4,8 @@ import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.whisper.base.WhisperSubtitleExtractor; import com.github.gtache.autosubtitle.subtitle.extractor.whisper.base.WhisperSubtitleExtractor;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/** /**
* Dagger module for Whisper * Dagger module for Whisper
@@ -16,5 +18,7 @@ public abstract class WhisperExtractorModule {
} }
@Binds @Binds
abstract SubtitleExtractor bindsSubtitleExtractor(final WhisperSubtitleExtractor extractor); @IntoMap
@StringKey("whisper")
abstract SubtitleExtractor<?> bindsSubtitleExtractor(final WhisperSubtitleExtractor extractor);
} }

View File

@@ -1,31 +0,0 @@
package com.github.gtache.autosubtitle.modules.subtitle.parser.json.whisper.base;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.parser.json.whisper.base.JSONSubtitleConverter;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import javax.inject.Singleton;
@Module
public abstract class WhisperJsonModule {
private WhisperJsonModule() {
}
@Binds
@IntoMap
@StringKey("json")
abstract SubtitleConverter bindsJSONSubtitleConverter(final JSONSubtitleConverter subtitleConverter);
@Provides
@Singleton
static ObjectMapper providesObjectMapper() {
return new ObjectMapper();
}
}

View File

@@ -2,16 +2,17 @@ package com.github.gtache.autosubtitle.modules.whisper.base;
import com.github.gtache.autosubtitle.modules.setup.whisper.base.WhisperSetupModule; import com.github.gtache.autosubtitle.modules.setup.whisper.base.WhisperSetupModule;
import com.github.gtache.autosubtitle.modules.subtitle.extractor.whisper.base.WhisperExtractorModule; import com.github.gtache.autosubtitle.modules.subtitle.extractor.whisper.base.WhisperExtractorModule;
import com.github.gtache.autosubtitle.modules.subtitle.parser.json.whisper.base.WhisperJsonModule;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.whisper.base.WhisperExtractionModelProvider; import com.github.gtache.autosubtitle.whisper.base.WhisperExtractionModelProvider;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/** /**
* Dagger module for Whisper * Dagger module for Whisper
*/ */
@Module(includes = {WhisperSetupModule.class, WhisperJsonModule.class, WhisperExtractorModule.class}) @Module(includes = {WhisperSetupModule.class, WhisperExtractorModule.class})
public abstract class WhisperModule { public abstract class WhisperModule {
private WhisperModule() { private WhisperModule() {
@@ -19,5 +20,7 @@ public abstract class WhisperModule {
} }
@Binds @Binds
@IntoMap
@StringKey("whisper")
abstract ExtractionModelProvider bindsExtractionModelProvider(final WhisperExtractionModelProvider provider); abstract ExtractionModelProvider bindsExtractionModelProvider(final WhisperExtractionModelProvider provider);
} }

View File

@@ -1,7 +1,9 @@
package com.github.gtache.autosubtitle.setup.whisper.base; package com.github.gtache.autosubtitle.setup.whisper.base;
import com.github.gtache.autosubtitle.modules.setup.whisper.base.Whisper;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.conda.CondaSetupManager; import com.github.gtache.autosubtitle.setup.conda.CondaSetupManager;
import com.github.gtache.autosubtitle.setup.whisper.AbstractWhisperSetupManager; import com.github.gtache.autosubtitle.setup.whisper.AbstractWhisperSetupManager;
import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration; import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration;
@@ -17,7 +19,7 @@ import java.time.Duration;
import java.util.List; import java.util.List;
/** /**
* {@link com.github.gtache.autosubtitle.setup.SetupManager} for Whisper * {@link SetupManager} for Whisper
*/ */
@Singleton @Singleton
public class WhisperSetupManager extends AbstractWhisperSetupManager { public class WhisperSetupManager extends AbstractWhisperSetupManager {
@@ -25,7 +27,7 @@ public class WhisperSetupManager extends AbstractWhisperSetupManager {
private static final Logger logger = LogManager.getLogger(WhisperSetupManager.class); private static final Logger logger = LogManager.getLogger(WhisperSetupManager.class);
@Inject @Inject
WhisperSetupManager(final CondaSetupManager condaSetupManager, final WhisperSetupConfiguration configuration, WhisperSetupManager(final CondaSetupManager condaSetupManager, @Whisper final WhisperSetupConfiguration configuration,
final ProcessRunner processRunner, final HttpClient httpClient) { final ProcessRunner processRunner, final HttpClient httpClient) {
super(condaSetupManager, configuration, processRunner, httpClient); super(condaSetupManager, configuration, processRunner, httpClient);
} }

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.subtitle.parser.json.whisper.base; package com.github.gtache.autosubtitle.subtitle.converter.json.whisper.base;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.subtitle.parser.json.whisper.base; package com.github.gtache.autosubtitle.subtitle.converter.json.whisper.base;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.subtitle.parser.json.whisper.base; package com.github.gtache.autosubtitle.subtitle.converter.json.whisper.base;
import java.util.List; import java.util.List;

View File

@@ -2,9 +2,9 @@ package com.github.gtache.autosubtitle.subtitle.extractor.whisper.base;
import com.github.gtache.autosubtitle.Language; import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.impl.OS; import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperVenvPath; import com.github.gtache.autosubtitle.modules.setup.whisper.base.WhisperVenvPath;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider; import com.github.gtache.autosubtitle.subtitle.converter.json.whisper.base.JSONSubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor; import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.whisper.AbstractWhisperSubtitleExtractor; import com.github.gtache.autosubtitle.subtitle.extractor.whisper.AbstractWhisperSubtitleExtractor;
@@ -24,9 +24,9 @@ public class WhisperSubtitleExtractor extends AbstractWhisperSubtitleExtractor {
@Inject @Inject
WhisperSubtitleExtractor(@WhisperVenvPath final Path venvPath, final SubtitleConverterProvider converterProvider, WhisperSubtitleExtractor(@WhisperVenvPath final Path venvPath, final JSONSubtitleConverter converter,
final ProcessRunner processRunner, final OS os) { final ProcessRunner processRunner, final OS os) {
super(venvPath, converterProvider, processRunner, os); super(venvPath, converter, processRunner, os);
} }
@Override @Override

View File

@@ -3,13 +3,13 @@
*/ */
module com.github.gtache.autosubtitle.whisper.base { module com.github.gtache.autosubtitle.whisper.base {
requires transitive com.github.gtache.autosubtitle.whisper.common; requires transitive com.github.gtache.autosubtitle.whisper.common;
requires com.fasterxml.jackson.databind;
requires com.github.gtache.autosubtitle.core;
requires org.apache.logging.log4j; requires org.apache.logging.log4j;
exports com.github.gtache.autosubtitle.setup.whisper.base; exports com.github.gtache.autosubtitle.setup.whisper.base;
exports com.github.gtache.autosubtitle.subtitle.converter.json.whisper.base;
exports com.github.gtache.autosubtitle.subtitle.extractor.whisper.base; exports com.github.gtache.autosubtitle.subtitle.extractor.whisper.base;
exports com.github.gtache.autosubtitle.whisper.base; exports com.github.gtache.autosubtitle.whisper.base;
exports com.github.gtache.autosubtitle.modules.setup.whisper.base; exports com.github.gtache.autosubtitle.modules.setup.whisper.base;
exports com.github.gtache.autosubtitle.modules.subtitle.extractor.whisper.base; exports com.github.gtache.autosubtitle.modules.subtitle.extractor.whisper.base;
exports com.github.gtache.autosubtitle.modules.whisper.base; exports com.github.gtache.autosubtitle.modules.whisper.base;

View File

@@ -1,25 +0,0 @@
package com.github.gtache.autosubtitle.modules.setup.whisper;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.modules.setup.conda.CondaSetupModule;
import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration;
import dagger.Module;
import dagger.Provides;
import java.nio.file.Path;
@Module(includes = CondaSetupModule.class)
public final class WhisperCommonSetupModule {
private WhisperCommonSetupModule() {
}
@Provides
static WhisperSetupConfiguration providesWhisperSetupConfiguration(@WhisperBundledRoot final Path root,
@WhisperVenvPath final Path venvPath,
@PythonVersion final String pythonVersion,
final OS os) {
return new WhisperSetupConfiguration(root, venvPath, pythonVersion, os);
}
}

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.whisper; package com.github.gtache.autosubtitle.setup.whisper;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.impl.OS; import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupAction; import com.github.gtache.autosubtitle.setup.SetupAction;
@@ -35,6 +36,11 @@ public abstract class AbstractWhisperSetupManager extends AbstractSetupManager {
this.configuration = requireNonNull(configuration); this.configuration = requireNonNull(configuration);
} }
@Override
public ToolType type() {
return ToolType.SUBTITLE_EXTRACTOR;
}
@Override @Override
protected SetupStatus getStatus() throws SetupException { protected SetupStatus getStatus() throws SetupException {
if (isWhisperInstalled()) { if (isWhisperInstalled()) {

View File

@@ -5,17 +5,16 @@ import com.github.gtache.autosubtitle.File;
import com.github.gtache.autosubtitle.Video; import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.impl.OS; import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection; import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.converter.ParseException; import com.github.gtache.autosubtitle.subtitle.converter.ParseException;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter; import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractException; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractException;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor; import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener; import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener;
import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractEventImpl; import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractEventImpl;
import com.github.gtache.autosubtitle.subtitle.impl.SubtitleImpl;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -34,7 +33,7 @@ import static java.util.Objects.requireNonNull;
/** /**
* Base implementation of {@link SubtitleExtractor} for Whisper * Base implementation of {@link SubtitleExtractor} for Whisper
*/ */
public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtractor<Subtitle> { public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtractor<SubtitleImpl> {
private static final Logger logger = LogManager.getLogger(AbstractWhisperSubtitleExtractor.class); private static final Logger logger = LogManager.getLogger(AbstractWhisperSubtitleExtractor.class);
@@ -44,14 +43,14 @@ public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtrac
private static final Pattern TQDM_PROGRESS_PATTERN = Pattern.compile("^(?<progress>\\d{1,3})%\\|.+"); private static final Pattern TQDM_PROGRESS_PATTERN = Pattern.compile("^(?<progress>\\d{1,3})%\\|.+");
private final Path venvPath; private final Path venvPath;
private final ProcessRunner processRunner; private final ProcessRunner processRunner;
private final SubtitleConverter converter; private final SubtitleConverter<SubtitleImpl> converter;
private final OS os; private final OS os;
private final Set<SubtitleExtractorListener> listeners; private final Set<SubtitleExtractorListener> listeners;
protected AbstractWhisperSubtitleExtractor(final Path venvPath, final SubtitleConverterProvider converterProvider, protected AbstractWhisperSubtitleExtractor(final Path venvPath, final SubtitleConverter<SubtitleImpl> converter,
final ProcessRunner processRunner, final OS os) { final ProcessRunner processRunner, final OS os) {
this.venvPath = requireNonNull(venvPath); this.venvPath = requireNonNull(venvPath);
this.converter = requireNonNull(converterProvider.getConverter("json")); this.converter = requireNonNull(converter);
this.processRunner = requireNonNull(processRunner); this.processRunner = requireNonNull(processRunner);
this.os = requireNonNull(os); this.os = requireNonNull(os);
this.listeners = new HashSet<>(); this.listeners = new HashSet<>();
@@ -78,16 +77,16 @@ public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtrac
@Override @Override
public SubtitleCollection<Subtitle> extract(final Video video, final ExtractOptions options) throws ExtractException { public SubtitleCollection<SubtitleImpl> extract(final Video video, final ExtractOptions options) throws ExtractException {
return extract(new AudioOrVideo(video), options); return extract(new AudioOrVideo(video), options);
} }
@Override @Override
public SubtitleCollection<Subtitle> extract(final Audio audio, final ExtractOptions options) throws ExtractException { public SubtitleCollection<SubtitleImpl> extract(final Audio audio, final ExtractOptions options) throws ExtractException {
return extract(new AudioOrVideo(audio), options); return extract(new AudioOrVideo(audio), options);
} }
private SubtitleCollection<Subtitle> extract(final AudioOrVideo av, final ExtractOptions options) throws ExtractException { private SubtitleCollection<SubtitleImpl> extract(final AudioOrVideo av, final ExtractOptions options) throws ExtractException {
if (av.inner() instanceof final File f) { if (av.inner() instanceof final File f) {
return extract(f.path(), options, av.info().duration()); return extract(f.path(), options, av.info().duration());
} else { } else {
@@ -99,7 +98,7 @@ public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtrac
} }
} }
private SubtitleCollection<Subtitle> dumpExtract(final AudioOrVideo av, final ExtractOptions options) throws ExtractException, IOException { private SubtitleCollection<SubtitleImpl> dumpExtract(final AudioOrVideo av, final ExtractOptions options) throws ExtractException, IOException {
final var path = Files.createTempFile(AUTOSUBTITLE, "." + av.info().format()); final var path = Files.createTempFile(AUTOSUBTITLE, "." + av.info().format());
try (final var in = av.getInputStream()) { try (final var in = av.getInputStream()) {
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING); Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
@@ -109,7 +108,7 @@ public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtrac
} }
} }
private SubtitleCollection<Subtitle> extract(final Path path, final ExtractOptions options, final long duration) throws ExtractException { private SubtitleCollection<SubtitleImpl> extract(final Path path, final ExtractOptions options, final long duration) throws ExtractException {
try { try {
final var outputDir = Files.createTempDirectory(AUTOSUBTITLE); final var outputDir = Files.createTempDirectory(AUTOSUBTITLE);
final var args = createArgs(path, options, outputDir); final var args = createArgs(path, options, outputDir);
@@ -137,7 +136,7 @@ public abstract class AbstractWhisperSubtitleExtractor implements SubtitleExtrac
} }
} }
private SubtitleCollection<Subtitle> parseResult(final Path subtitleFile, final ExtractOptions options) throws ExtractException { private SubtitleCollection<SubtitleImpl> parseResult(final Path subtitleFile, final ExtractOptions options) throws ExtractException {
try { try {
return converter.parse(subtitleFile, options.parseOptions()); return converter.parse(subtitleFile, options.parseOptions());
} catch (final ParseException e) { } catch (final ParseException e) {

View File

@@ -10,5 +10,4 @@ module com.github.gtache.autosubtitle.whisper.common {
exports com.github.gtache.autosubtitle.whisper; exports com.github.gtache.autosubtitle.whisper;
exports com.github.gtache.autosubtitle.setup.whisper; exports com.github.gtache.autosubtitle.setup.whisper;
exports com.github.gtache.autosubtitle.subtitle.extractor.whisper; exports com.github.gtache.autosubtitle.subtitle.extractor.whisper;
exports com.github.gtache.autosubtitle.modules.setup.whisper;
} }

View File

@@ -1,23 +0,0 @@
package com.github.gtache.autosubtitle.modules.setup.whisper;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration;
import org.junit.jupiter.api.Test;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
class TestWhisperCommonSetupModule {
@Test
void testWhisperSetupConfiguration() {
final var root = mock(Path.class);
final var venvPath = mock(Path.class);
final var pythonVersion = "3.10";
final var os = OS.LINUX;
final var expected = new WhisperSetupConfiguration(root, venvPath, pythonVersion, os);
assertEquals(expected, WhisperCommonSetupModule.providesWhisperSetupConfiguration(root, venvPath, pythonVersion, os));
}
}

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.setup.whisper; package com.github.gtache.autosubtitle.setup.whisper;
import com.github.gtache.autosubtitle.ToolType;
import com.github.gtache.autosubtitle.impl.OS; import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
@@ -53,6 +54,11 @@ class TestAbstractWhisperSetupManager {
assertEquals(BUNDLE_INSTALLED, setupManager.getStatus()); assertEquals(BUNDLE_INSTALLED, setupManager.getStatus());
} }
@Test
void testType() {
assertEquals(ToolType.SUBTITLE_EXTRACTOR, setupManager.type());
}
@Test @Test
void testInstallAlreadyInstalled() throws SetupException { void testInstallAlreadyInstalled() throws SetupException {
final var venvPath = Paths.get("path"); final var venvPath = Paths.get("path");

View File

@@ -9,17 +9,16 @@ import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessListener; import com.github.gtache.autosubtitle.process.ProcessListener;
import com.github.gtache.autosubtitle.process.ProcessResult; import com.github.gtache.autosubtitle.process.ProcessResult;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection; import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.converter.ParseException; import com.github.gtache.autosubtitle.subtitle.converter.ParseException;
import com.github.gtache.autosubtitle.subtitle.converter.ParseOptions; import com.github.gtache.autosubtitle.subtitle.converter.ParseOptions;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter; import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractException; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractException;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener; import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener;
import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractEventImpl; import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractEventImpl;
import com.github.gtache.autosubtitle.subtitle.impl.SubtitleImpl;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@@ -42,8 +41,7 @@ import static org.mockito.Mockito.*;
class TestAbstractWhisperSubtitleExtractor { class TestAbstractWhisperSubtitleExtractor {
private final Path venvPath; private final Path venvPath;
private final SubtitleConverter<Subtitle> converter; private final SubtitleConverter<SubtitleImpl> converter;
private final SubtitleConverterProvider converterProvider;
private final ProcessRunner processRunner; private final ProcessRunner processRunner;
private final ProcessListener processListener; private final ProcessListener processListener;
private final ProcessResult processResult; private final ProcessResult processResult;
@@ -54,17 +52,16 @@ class TestAbstractWhisperSubtitleExtractor {
private final VideoInfo videoInfo; private final VideoInfo videoInfo;
private final ExtractOptions options; private final ExtractOptions options;
private final ParseOptions parseOptions; private final ParseOptions parseOptions;
private final SubtitleCollection<Subtitle> collection; private final SubtitleCollection<SubtitleImpl> collection;
TestAbstractWhisperSubtitleExtractor(@Mock final SubtitleConverterProvider converterProvider, @Mock final SubtitleConverter<Subtitle> converter, TestAbstractWhisperSubtitleExtractor(@Mock final SubtitleConverter<SubtitleImpl> converter,
@Mock final ProcessRunner processRunner, @Mock final ProcessListener processListener, @Mock final ProcessRunner processRunner, @Mock final ProcessListener processListener,
@Mock final ProcessResult processResult, @Mock final VideoInfo videoInfo, @Mock final ProcessResult processResult, @Mock final VideoInfo videoInfo,
@Mock final AudioInfo audioInfo, @Mock final ExtractOptions options, @Mock final AudioInfo audioInfo, @Mock final ExtractOptions options,
@Mock final ParseOptions parseOptions, @Mock final SubtitleCollection<Subtitle> collection) { @Mock final ParseOptions parseOptions, @Mock final SubtitleCollection<SubtitleImpl> collection) {
this.venvPath = Path.of("venv"); this.venvPath = Path.of("venv");
this.os = OS.LINUX; this.os = OS.LINUX;
this.converterProvider = Objects.requireNonNull(converterProvider);
this.converter = Objects.requireNonNull(converter); this.converter = Objects.requireNonNull(converter);
this.processRunner = Objects.requireNonNull(processRunner); this.processRunner = Objects.requireNonNull(processRunner);
this.processListener = Objects.requireNonNull(processListener); this.processListener = Objects.requireNonNull(processListener);
@@ -78,13 +75,12 @@ class TestAbstractWhisperSubtitleExtractor {
@BeforeEach @BeforeEach
void beforeEach() throws IOException { void beforeEach() throws IOException {
doReturn(converter).when(converterProvider).getConverter("json");
when(processRunner.startListen(anyList())).thenReturn(processListener); when(processRunner.startListen(anyList())).thenReturn(processListener);
when(processListener.join(Duration.ofHours(1))).thenReturn(processResult); when(processListener.join(Duration.ofHours(1))).thenReturn(processResult);
when(audioInfo.format()).thenReturn("mp3"); when(audioInfo.format()).thenReturn("mp3");
when(videoInfo.format()).thenReturn("mp4"); when(videoInfo.format()).thenReturn("mp4");
when(options.parseOptions()).thenReturn(parseOptions); when(options.parseOptions()).thenReturn(parseOptions);
this.extractor = new DummyWhisperSubtitleExtractor(venvPath, converterProvider, processRunner, os); this.extractor = new DummyWhisperSubtitleExtractor(venvPath, converter, processRunner, os);
} }
@Test @Test
@@ -200,14 +196,14 @@ class TestAbstractWhisperSubtitleExtractor {
@Test @Test
void testGetPythonPathWindows() { void testGetPythonPathWindows() {
final var windowsExtractor = new DummyWhisperSubtitleExtractor(venvPath, converterProvider, processRunner, OS.WINDOWS); final var windowsExtractor = new DummyWhisperSubtitleExtractor(venvPath, converter, processRunner, OS.WINDOWS);
assertEquals(venvPath.resolve("python.exe"), windowsExtractor.getPythonPath()); assertEquals(venvPath.resolve("python.exe"), windowsExtractor.getPythonPath());
} }
private static final class DummyWhisperSubtitleExtractor extends AbstractWhisperSubtitleExtractor { private static final class DummyWhisperSubtitleExtractor extends AbstractWhisperSubtitleExtractor {
private DummyWhisperSubtitleExtractor(final Path venvPath, final SubtitleConverterProvider converterProvider, final ProcessRunner processRunner, final OS os) { private DummyWhisperSubtitleExtractor(final Path venvPath, final SubtitleConverter<SubtitleImpl> converter, final ProcessRunner processRunner, final OS os) {
super(venvPath, converterProvider, processRunner, os); super(venvPath, converter, processRunner, os);
} }
@Override @Override

View File

@@ -16,9 +16,5 @@
<groupId>com.github.gtache.autosubtitle</groupId> <groupId>com.github.gtache.autosubtitle</groupId>
<artifactId>autosubtitle-whisper-common</artifactId> <artifactId>autosubtitle-whisper-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -0,0 +1,16 @@
package com.github.gtache.autosubtitle.modules.setup.whisperx;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
public @interface WhisperX {
}

View File

@@ -0,0 +1,16 @@
package com.github.gtache.autosubtitle.modules.setup.whisperx;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
public @interface WhisperXBundledRoot {
}

View File

@@ -0,0 +1,16 @@
package com.github.gtache.autosubtitle.modules.setup.whisperx;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
public @interface WhisperXPythonVersion {
}

View File

@@ -1,43 +1,59 @@
package com.github.gtache.autosubtitle.modules.setup.whisperx; package com.github.gtache.autosubtitle.modules.setup.whisperx;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.modules.setup.conda.CondaSetupModule;
import com.github.gtache.autosubtitle.modules.setup.impl.SubtitleExtractorSetup; import com.github.gtache.autosubtitle.modules.setup.impl.SubtitleExtractorSetup;
import com.github.gtache.autosubtitle.modules.setup.impl.ToolsRoot; import com.github.gtache.autosubtitle.modules.setup.impl.ToolsRoot;
import com.github.gtache.autosubtitle.modules.setup.whisper.PythonVersion;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperBundledRoot;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperCommonSetupModule;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperVenvPath;
import com.github.gtache.autosubtitle.setup.SetupManager; import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration;
import com.github.gtache.autosubtitle.setup.whisperx.WhisperXSetupManager; import com.github.gtache.autosubtitle.setup.whisperx.WhisperXSetupManager;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import java.nio.file.Path; import java.nio.file.Path;
/** /**
* Setup module for Whisper * Setup module for Whisper
*/ */
@Module(includes = WhisperCommonSetupModule.class) @Module(includes = CondaSetupModule.class)
public abstract class WhisperXSetupModule { public abstract class WhisperXSetupModule {
@Binds @Binds
@SubtitleExtractorSetup @SubtitleExtractorSetup
@IntoMap
@StringKey("whisperx")
abstract SetupManager bindsSubtitleExtractorSetupManager(final WhisperXSetupManager manager); abstract SetupManager bindsSubtitleExtractorSetupManager(final WhisperXSetupManager manager);
@Binds
@SubtitleExtractorSetup
abstract SetupManager bindsDefaultSubtitleExtractorSetupManager(final WhisperXSetupManager manager);
@Provides @Provides
@PythonVersion @WhisperXPythonVersion
static String providesPythonVersion() { static String providesPythonVersion() {
return "3.10"; return "3.10";
} }
@Provides @Provides
@WhisperBundledRoot @WhisperXBundledRoot
static Path providesWhisperXBundledRoot(@ToolsRoot final Path root) { static Path providesWhisperXBundledRoot(@ToolsRoot final Path root) {
return root.resolve("whisperx"); return root.resolve("whisperx");
} }
@Provides @Provides
@WhisperVenvPath @WhisperXVenvPath
static Path providesWhisperXVenvPath(@WhisperBundledRoot final Path root) { static Path providesWhisperXVenvPath(@WhisperXBundledRoot final Path root) {
return root.resolve("whisperx-env"); return root.resolve("whisperx-env");
} }
@Provides
@WhisperX
static WhisperSetupConfiguration providesWhisperSetupConfiguration(@WhisperXBundledRoot final Path root,
@WhisperXVenvPath final Path venvPath,
@WhisperXPythonVersion final String pythonVersion,
final OS os) {
return new WhisperSetupConfiguration(root, venvPath, pythonVersion, os);
}
} }

View File

@@ -0,0 +1,16 @@
package com.github.gtache.autosubtitle.modules.setup.whisperx;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
public @interface WhisperXVenvPath {
}

View File

@@ -4,6 +4,8 @@ import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.whisperx.WhisperXSubtitleExtractor; import com.github.gtache.autosubtitle.subtitle.extractor.whisperx.WhisperXSubtitleExtractor;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/** /**
* Dagger module for Whisper * Dagger module for Whisper
@@ -16,5 +18,10 @@ public abstract class WhisperXExtractorModule {
} }
@Binds @Binds
abstract SubtitleExtractor bindsSubtitleExtractor(final WhisperXSubtitleExtractor extractor); @IntoMap
@StringKey("whisperx")
abstract SubtitleExtractor<?> bindsSubtitleExtractor(final WhisperXSubtitleExtractor extractor);
@Binds
abstract SubtitleExtractor providesDefaultSubtitleExtractor(final WhisperXSubtitleExtractor extractor);
} }

View File

@@ -2,16 +2,17 @@ package com.github.gtache.autosubtitle.modules.whisperx;
import com.github.gtache.autosubtitle.modules.setup.whisperx.WhisperXSetupModule; import com.github.gtache.autosubtitle.modules.setup.whisperx.WhisperXSetupModule;
import com.github.gtache.autosubtitle.modules.subtitle.extractor.whisperx.WhisperXExtractorModule; import com.github.gtache.autosubtitle.modules.subtitle.extractor.whisperx.WhisperXExtractorModule;
import com.github.gtache.autosubtitle.modules.subtitle.parser.json.whisperx.WhisperXJsonModule;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider; import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.whisperx.WhisperXExtractionModelProvider; import com.github.gtache.autosubtitle.whisperx.WhisperXExtractionModelProvider;
import dagger.Binds; import dagger.Binds;
import dagger.Module; import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/** /**
* Dagger module for Whisper * Dagger module for Whisper
*/ */
@Module(includes = {WhisperXSetupModule.class, WhisperXJsonModule.class, WhisperXExtractorModule.class}) @Module(includes = {WhisperXSetupModule.class, WhisperXExtractorModule.class})
public abstract class WhisperXModule { public abstract class WhisperXModule {
private WhisperXModule() { private WhisperXModule() {
@@ -19,5 +20,10 @@ public abstract class WhisperXModule {
} }
@Binds @Binds
@IntoMap
@StringKey("whisperx")
abstract ExtractionModelProvider bindsExtractionModelProvider(final WhisperXExtractionModelProvider provider); abstract ExtractionModelProvider bindsExtractionModelProvider(final WhisperXExtractionModelProvider provider);
@Binds
abstract ExtractionModelProvider bindsDefaultExtractionModelProvider(final WhisperXExtractionModelProvider provider);
} }

View File

@@ -1,7 +1,10 @@
package com.github.gtache.autosubtitle.setup.whisperx; package com.github.gtache.autosubtitle.setup.whisperx;
import com.github.gtache.autosubtitle.modules.setup.whisperx.WhisperX;
import com.github.gtache.autosubtitle.process.ProcessRunner; import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException; import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.SetupUserBridge;
import com.github.gtache.autosubtitle.setup.conda.CondaSetupManager; import com.github.gtache.autosubtitle.setup.conda.CondaSetupManager;
import com.github.gtache.autosubtitle.setup.whisper.AbstractWhisperSetupManager; import com.github.gtache.autosubtitle.setup.whisper.AbstractWhisperSetupManager;
import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration; import com.github.gtache.autosubtitle.setup.whisper.WhisperSetupConfiguration;
@@ -16,18 +19,22 @@ import java.nio.file.Files;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
import static java.util.Objects.requireNonNull;
/** /**
* {@link com.github.gtache.autosubtitle.setup.SetupManager} for WhisperX * {@link SetupManager} for WhisperX
*/ */
@Singleton @Singleton
public class WhisperXSetupManager extends AbstractWhisperSetupManager { public class WhisperXSetupManager extends AbstractWhisperSetupManager {
private static final Logger logger = LogManager.getLogger(WhisperXSetupManager.class); private static final Logger logger = LogManager.getLogger(WhisperXSetupManager.class);
private final SetupUserBridge setupUserBridge;
@Inject @Inject
WhisperXSetupManager(final CondaSetupManager condaSetupManager, final WhisperSetupConfiguration configuration, WhisperXSetupManager(final CondaSetupManager condaSetupManager, @WhisperX final WhisperSetupConfiguration configuration,
final ProcessRunner processRunner, final HttpClient httpClient) { final SetupUserBridge setupUserBridge, final ProcessRunner processRunner, final HttpClient httpClient) {
super(condaSetupManager, configuration, processRunner, httpClient); super(condaSetupManager, configuration, processRunner, httpClient);
this.setupUserBridge = requireNonNull(setupUserBridge);
} }
@Override @Override
@@ -35,6 +42,7 @@ public class WhisperXSetupManager extends AbstractWhisperSetupManager {
return "WhisperX"; return "WhisperX";
} }
@Override @Override
protected void installWhisper() throws SetupException { protected void installWhisper() throws SetupException {
final var path = getPythonPath(); final var path = getPythonPath();
@@ -42,6 +50,7 @@ public class WhisperXSetupManager extends AbstractWhisperSetupManager {
logger.info("Installing whisper"); logger.info("Installing whisper");
final var result = processRunner().run(List.of(path.toString(), "-m", "pip", "install", "-U", "git+https://github.com/m-bain/whisperx.git", "numpy<2"), Duration.ofMinutes(15)); final var result = processRunner().run(List.of(path.toString(), "-m", "pip", "install", "-U", "git+https://github.com/m-bain/whisperx.git", "numpy<2"), Duration.ofMinutes(15));
if (result.exitCode() == 0) { if (result.exitCode() == 0) {
checkInstallCuda();
logger.info("Whisper installed"); logger.info("Whisper installed");
} else { } else {
throw new SetupException("Error installing whisper: " + result.output()); throw new SetupException("Error installing whisper: " + result.output());
@@ -51,6 +60,12 @@ public class WhisperXSetupManager extends AbstractWhisperSetupManager {
} }
} }
private void checkInstallCuda() {
if (setupUserBridge.askForUserConfirmation("WhisperX can use CUDA. Do you want to install it?")) {
//TODO install CUDA "conda install cudnn=8"
}
}
@Override @Override
protected boolean isWhisperInstalled() throws SetupException { protected boolean isWhisperInstalled() throws SetupException {
final var path = getPythonPath(); final var path = getPythonPath();

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.subtitle.parser.json.whisperx; package com.github.gtache.autosubtitle.subtitle.converter.json.whisperx;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.github.gtache.autosubtitle.subtitle.parser.json.whisperx; package com.github.gtache.autosubtitle.subtitle.converter.json.whisperx;
public record JSONSubtitleWords(String word, double start, double end, double score) { public record JSONSubtitleWords(String word, double start, double end, double score) {
} }

Some files were not shown because too many files have changed in this diff Show More