diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index d2f030c..e7de95b 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -8,120 +8,15 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -184,47 +79,35 @@
- {
+ "keyToString": {
+ "Application.Main.executor": "Run",
+ "JUnit.TestASSSubtitleConverter.executor": "Run",
+ "JUnit.TestAbstractSetupManager.executor": "Run",
+ "JUnit.TestFFmpegVideoConverter.executor": "Run",
+ "JUnit.TestFXSubtitlesBinder.executor": "Run",
+ "Maven.autosubtitle [clean,package,-DskipTests].executor": "Run",
+ "Maven.autosubtitle [clean,package].executor": "Run",
+ "Maven.autosubtitle [clean].executor": "Run",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "SHARE_PROJECT_CONFIGURATION_FILES": "true",
+ "com.codeium.enabled": "true",
+ "git-widget-placeholder": "master",
+ "ignore.virus.scanning.warn.message": "true",
+ "kotlin-language-version-configured": "true",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "project.structure.last.edited": "Modules",
+ "project.structure.proportion": "0.0",
+ "project.structure.side.proportion": "0.0",
+ "run.code.analysis.last.selected.profile": "aDefault",
+ "settings.editor.selected.configurable": "actions.on.save",
+ "vue.rearranger.settings.migration": "true"
}
-}]]>
-
-
-
-
-
-
+}
@@ -242,11 +125,11 @@
-
+
-
+
@@ -427,11 +310,11 @@
+
-
-
+
@@ -452,7 +335,10 @@
1726946764733
-
+
+
+
+
diff --git a/client/src/main/java/com/github/gtache/autosubtitle/client/AbstractClient.java b/client/src/main/java/com/github/gtache/autosubtitle/client/AbstractClient.java
new file mode 100644
index 0000000..8f9a111
--- /dev/null
+++ b/client/src/main/java/com/github/gtache/autosubtitle/client/AbstractClient.java
@@ -0,0 +1,4 @@
+package com.github.gtache.autosubtitle.client;
+
+public abstract class AbstractClient {
+}
diff --git a/client/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/client/RemoteSubtitleExtractor.java b/client/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/client/RemoteSubtitleExtractor.java
index c7bbee9..c28ae7b 100644
--- a/client/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/client/RemoteSubtitleExtractor.java
+++ b/client/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/client/RemoteSubtitleExtractor.java
@@ -6,19 +6,20 @@ import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.impl.AbstractSubtitleExtractor;
+import com.github.gtache.autosubtitle.subtitle.impl.SubtitleImpl;
/**
* {@link SubtitleExtractor} using a remote API
*/
-public class RemoteSubtitleExtractor extends AbstractSubtitleExtractor {
+public class RemoteSubtitleExtractor extends AbstractSubtitleExtractor {
@Override
- public SubtitleCollection extract(final Video video, final ExtractOptions options) {
+ public SubtitleCollection extract(final Video video, final ExtractOptions options) {
throw new UnsupportedOperationException();
}
@Override
- public SubtitleCollection extract(final Audio audio, final ExtractOptions options) {
+ public SubtitleCollection extract(final Audio audio, final ExtractOptions options) {
throw new UnsupportedOperationException();
}
}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/impl/AbstractSubtitleExtractor.java b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/impl/AbstractSubtitleExtractor.java
index a5ec465..9e0bf25 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/impl/AbstractSubtitleExtractor.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/extractor/impl/AbstractSubtitleExtractor.java
@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.subtitle.extractor.impl;
+import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractEvent;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractor;
import com.github.gtache.autosubtitle.subtitle.extractor.SubtitleExtractorListener;
@@ -10,7 +11,7 @@ import java.util.Set;
/**
* Base implementation of {@link SubtitleExtractor}
*/
-public abstract class AbstractSubtitleExtractor implements SubtitleExtractor {
+public abstract class AbstractSubtitleExtractor implements SubtitleExtractor {
private final Set listeners;
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java
index 25adcf2..0cd5abe 100644
--- a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/ffmpeg/FFmpegSetupManager.java
@@ -7,8 +7,6 @@ import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupManager;
import com.github.gtache.autosubtitle.setup.SetupStatus;
import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import javax.inject.Inject;
import java.io.IOException;
@@ -27,7 +25,6 @@ import static java.util.Objects.requireNonNull;
*/
//TODO add gpg/signature check
public class FFmpegSetupManager extends AbstractSetupManager {
- private static final Logger logger = LogManager.getLogger(FFmpegSetupManager.class);
private final FFmpegSetupConfiguration configuration;
private final ArchiverProvider archiverProvider;
diff --git a/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/ParametersBundle_fr.properties b/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/ParametersBundle_fr.properties
index bc70283..9626b7e 100644
--- a/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/ParametersBundle_fr.properties
+++ b/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/ParametersBundle_fr.properties
@@ -4,4 +4,5 @@ parameters.extraction.model.label=Mod\u00E8le utilis\u00E9 pour l'extraction des
parameters.subtitles.font.family=Police par d\u00E9faut pour les sous-titres
parameters.subtitles.font.size=Taille de la police par d\u00E9faut pour les sous-titres
parameters.subtitles.max.length.label=Taille maximale d'une ligne de sous-titres (caract\u00E8res)
+parameters.subtitles.max.lines.label=Nombre de lignes maximum pour les sous-titres
parameters.subtitles.output.format=Format de sortie pour les sous-titres
\ No newline at end of file
diff --git a/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle.properties b/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle.properties
index 770d055..0187f71 100644
--- a/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle.properties
+++ b/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle.properties
@@ -7,6 +7,9 @@ subtitles.export.error.title=Error exporting
subtitles.language.label=Video language
subtitles.load.error.label=Error loading subtitles : {0}
subtitles.load.error.title=Error loading
+subtitles.menu.add.label=Add
+subtitles.menu.delete.label=Delete
+subtitles.menu.duplicate.label=Duplicate
subtitles.save.error.label=Error saving subtitles : {0}
subtitles.save.error.title=Error saving
subtitles.table.column.from.label=From
diff --git a/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle_fr.properties b/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle_fr.properties
index 9ea4315..73f9539 100644
--- a/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle_fr.properties
+++ b/gui/core/src/main/resources/com/github/gtache/autosubtitle/gui/impl/SubtitlesBundle_fr.properties
@@ -7,6 +7,9 @@ subtitles.export.error.title=Erreur d'export
subtitles.language.label=Langage de la vid\u00E9o
subtitles.load.error.label=Erreur de chargement des sous-titres : {0}
subtitles.load.error.title=Erreur de chargement
+subtitles.menu.add.label=Ajouter
+subtitles.menu.delete.label=Supprimer
+subtitles.menu.duplicate.label=Dupliquer
subtitles.save.error.label=Erreur de sauvegarde des sous-titres : {0}
subtitles.save.error.title=Erreur lors de la sauvegarde
subtitles.table.column.from.label=De
diff --git a/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java b/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java
index f8d51d3..af666ec 100644
--- a/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java
+++ b/gui/fx/src/main/java/com/github/gtache/autosubtitle/gui/subtitles/fx/FXSubtitlesController.java
@@ -19,12 +19,15 @@ import javafx.collections.MapChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.MenuItem;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
+import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyCode;
import javafx.stage.FileChooser;
import javafx.stage.Window;
@@ -131,38 +134,44 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
}
});
- translationsCombobox.setOnAction(e -> {
- final var value = translationsCombobox.getValue();
- if (value != null && !model.collections().containsKey(value)) {
- model.setTranslating(true);
- CompletableFuture.supplyAsync(() -> {
- final var mainCollection = model.collections().get(model.videoLanguage());
- try {
- if (mainCollection == null) {
- return translator.translate(model.selectedCollection(), value);
- } else {
- return translator.translate(mainCollection, value);
- }
- } catch (final TranslationException ex) {
- throw new CompletionException(ex);
- }
- }).whenCompleteAsync((r, t) -> {
- if (t == null) {
- loadCollection(r);
- model.setSelectedCollection(model.collections().get(value));
- } else {
- logger.error("Error while translating to {}", value, t);
- final var newCollection = new ObservableSubtitleCollectionImpl();
- loadCollection(newCollection);
- model.setSelectedCollection(newCollection);
- }
- model.setTranslating(false);
- }, Platform::runLater);
- }
- });
+ translationsCombobox.setOnAction(e -> translateToNewLanguage());
binder.createBindings();
}
+ private void translateToNewLanguage() {
+ final var value = translationsCombobox.getValue();
+ if (value != null && !model.collections().containsKey(value)) {
+ model.setTranslating(true);
+ CompletableFuture.supplyAsync(() -> {
+ final var mainCollection = model.collections().get(model.videoLanguage());
+ try {
+ if (mainCollection == null) {
+ if (model.selectedCollection() == null) {
+ return null;
+ } else {
+ return translator.translate(model.selectedCollection(), value);
+ }
+ } else {
+ return translator.translate(mainCollection, value);
+ }
+ } catch (final TranslationException ex) {
+ throw new CompletionException(ex);
+ }
+ }).whenCompleteAsync((r, t) -> {
+ if (r == null) {
+ logger.error("Error while translating to {}", value, t);
+ final var newCollection = new ObservableSubtitleCollectionImpl();
+ loadCollection(newCollection);
+ model.setSelectedCollection(newCollection);
+ } else {
+ loadCollection(r);
+ model.setSelectedCollection(model.collections().get(value));
+ }
+ model.setTranslating(false);
+ }, Platform::runLater);
+ }
+ }
+
private void bindTable() {
subtitlesTable.setItems(model.selectedSubtitles());
subtitlesTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -182,9 +191,7 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
e.consume();
}
});
- subtitlesTable.setOnContextMenuRequested(e -> {
- //TODO menu with copy, delete
- });
+ subtitlesTable.setOnContextMenuRequested(this::showContextMenu);
startColumn.setCellFactory(TextFieldTableCell.forTableColumn(new TimeStringConverter(timeFormatter)));
startColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue() == null ? null : param.getValue().start()));
startColumn.setOnEditCommit(e -> {
@@ -214,6 +221,30 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
}
+ private void showContextMenu(final ContextMenuEvent e) {
+ if (model.selectedCollection() != null) {
+ final var deleteMenuItem = new MenuItem(resources.getString("subtitles.menu.delete.label"));
+ deleteMenuItem.setOnAction(ignored -> deleteSelectedSubtitles());
+ final var addMenuItem = new MenuItem(resources.getString("subtitles.menu.add.label"));
+ addMenuItem.setOnAction(ignored -> addNewSubtitle());
+ final var duplicateMenuItem = new MenuItem(resources.getString("subtitles.menu.duplicate.label"));
+ duplicateMenuItem.setOnAction(ignored -> duplicateSelectedSubtitles());
+ final var menu = new ContextMenu(addMenuItem);
+ if (!model.selectedSubtitles().isEmpty()) {
+ menu.getItems().addAll(duplicateMenuItem, deleteMenuItem);
+ }
+ menu.show(subtitlesTable, e.getScreenX(), e.getScreenY());
+ }
+ }
+
+ private void duplicateSelectedSubtitles() {
+ final var selected = model.selectedSubtitles();
+ if (!selected.isEmpty()) {
+ model.selectedCollection().observableSubtitles().addAll(selected.stream().map(ObservableSubtitleImpl::new).toList());
+ model.selectedCollection().observableSubtitles().sort(Comparator.comparingLong(ObservableSubtitleImpl::start));
+ }
+ }
+
private void manageTabs() {
final var toRemove = new ArrayList();
final var toAdd = new ArrayList();
@@ -247,7 +278,13 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
@FXML
private void addPressed() {
- model.selectedCollection().subtitles().add(new ObservableSubtitleImpl(resources.getString("subtitles.add.prompt.label")));
+ addNewSubtitle();
+ }
+
+ private void addNewSubtitle() {
+ if (model.selectedCollection() != null) {
+ model.selectedCollection().subtitles().add(new ObservableSubtitleImpl(resources.getString("subtitles.add.prompt.label")));
+ }
}
@FXML