Pipeline working, implements FFmpegSetupManager
This commit is contained in:
@@ -4,7 +4,6 @@ import com.github.gtache.autosubtitle.gui.impl.CombinedResourceBundle;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.ResourceBundle;
|
||||
@@ -13,9 +12,12 @@ import java.util.ResourceBundle;
|
||||
* Dagger module for GUI
|
||||
*/
|
||||
@Module
|
||||
public class GuiCoreModule {
|
||||
public final class GuiCoreModule {
|
||||
|
||||
private GuiCoreModule() {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ResourceBundle providesBundle() {
|
||||
return new CombinedResourceBundle(ResourceBundle.getBundle("com.github.gtache.autosubtitle.gui.impl.MainBundle"),
|
||||
ResourceBundle.getBundle("com.github.gtache.autosubtitle.gui.impl.SetupBundle"),
|
||||
@@ -25,7 +27,6 @@ public class GuiCoreModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Play
|
||||
static byte[] providesPlayImage() {
|
||||
try (final var in = GuiCoreModule.class.getResourceAsStream("/com/github/gtache/autosubtitle/gui/impl/play_64.png")) {
|
||||
@@ -36,7 +37,6 @@ public class GuiCoreModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Pause
|
||||
static byte[] providesPauseImage() {
|
||||
try (final var in = GuiCoreModule.class.getResourceAsStream("/com/github/gtache/autosubtitle/gui/impl/pause_64.png")) {
|
||||
@@ -47,14 +47,12 @@ public class GuiCoreModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@FontFamily
|
||||
static String providesFontFamily() {
|
||||
return "Arial";
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@FontSize
|
||||
static int providesFontSize() {
|
||||
return 12;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>autosubtitle-fx</artifactId>
|
||||
<artifactId>autosubtitle-gui-fx</artifactId>
|
||||
|
||||
<properties>
|
||||
<controlsfx.version>11.2.1</controlsfx.version>
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package com.github.gtache.autosubtitle.gui.fx;
|
||||
|
||||
import com.github.gtache.autosubtitle.File;
|
||||
import com.github.gtache.autosubtitle.gui.MediaController;
|
||||
import com.github.gtache.autosubtitle.gui.TimeFormatter;
|
||||
import com.github.gtache.autosubtitle.impl.FileVideoImpl;
|
||||
import com.github.gtache.autosubtitle.modules.gui.impl.Pause;
|
||||
import com.github.gtache.autosubtitle.modules.gui.impl.Play;
|
||||
import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
|
||||
import com.github.gtache.autosubtitle.subtitle.Subtitle;
|
||||
import com.github.gtache.autosubtitle.subtitle.gui.fx.SubtitleLabel;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Cursor;
|
||||
@@ -31,6 +33,11 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -62,6 +69,8 @@ public class FXMediaController implements MediaController {
|
||||
private final Image playImage;
|
||||
private final Image pauseImage;
|
||||
|
||||
private final List<Long> startTimes;
|
||||
|
||||
private boolean wasPlaying;
|
||||
|
||||
@Inject
|
||||
@@ -72,6 +81,7 @@ public class FXMediaController implements MediaController {
|
||||
this.timeFormatter = requireNonNull(timeFormatter);
|
||||
this.playImage = requireNonNull(playImage);
|
||||
this.pauseImage = requireNonNull(pauseImage);
|
||||
this.startTimes = new ArrayList<>();
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -101,50 +111,78 @@ public class FXMediaController implements MediaController {
|
||||
if (videoView.getMediaPlayer() != null) {
|
||||
videoView.getMediaPlayer().dispose();
|
||||
}
|
||||
if (newValue instanceof final FileVideoImpl fileVideo) {
|
||||
final var media = new Media(fileVideo.path().toUri().toString());
|
||||
final var player = new MediaPlayer(media);
|
||||
player.currentTimeProperty().addListener((ignored, oldTime, newTime) -> {
|
||||
final var millis = newTime.toMillis();
|
||||
playSlider.setValue(millis);
|
||||
stackPane.getChildren().removeIf(Label.class::isInstance);
|
||||
model.subtitles().forEach(s -> {
|
||||
//TODO optimize using e.g. direction of playback
|
||||
if (s.start() <= millis && s.end() >= millis) {
|
||||
logger.info("Adding label {} at {}", s, millis);
|
||||
final var label = createDraggableLabel(s);
|
||||
stackPane.getChildren().add(label);
|
||||
}
|
||||
});
|
||||
});
|
||||
playSlider.setOnMousePressed(e -> {
|
||||
wasPlaying = model.isPlaying();
|
||||
model.setIsPlaying(false);
|
||||
});
|
||||
playSlider.valueProperty().addListener(observable1 -> {
|
||||
if (playSlider.isValueChanging()) {
|
||||
seek((long) playSlider.getValue());
|
||||
}
|
||||
});
|
||||
playSlider.setOnMouseReleased(e -> {
|
||||
final var value = playSlider.getValue();
|
||||
Platform.runLater(() -> {
|
||||
seek((long) value);
|
||||
model.setIsPlaying(wasPlaying);
|
||||
});
|
||||
});
|
||||
player.volumeProperty().bindBidirectional(model.volumeProperty());
|
||||
player.setOnPlaying(() -> model.setIsPlaying(true));
|
||||
player.setOnPaused(() -> model.setIsPlaying(false));
|
||||
player.setOnEndOfMedia(() -> model.setIsPlaying(false));
|
||||
playSlider.setMax(model.duration());
|
||||
playSlider.setValue(0L);
|
||||
videoView.setMediaPlayer(player);
|
||||
if (newValue instanceof final File file) {
|
||||
loadFileVideo(file.path());
|
||||
} else {
|
||||
logger.error("Unsupported video type : {}", newValue);
|
||||
}
|
||||
});
|
||||
|
||||
model.subtitles().addListener((ListChangeListener<EditableSubtitle>) c -> {
|
||||
startTimes.clear();
|
||||
model.subtitles().stream().mapToLong(Subtitle::start).forEach(startTimes::add);
|
||||
});
|
||||
bindPlayButton();
|
||||
binder.createBindings();
|
||||
}
|
||||
|
||||
private void loadFileVideo(final Path fileVideoPath) {
|
||||
final var media = new Media(fileVideoPath.toUri().toString());
|
||||
final var player = new MediaPlayer(media);
|
||||
player.statusProperty().addListener((observable12, oldValue1, newValue1) ->
|
||||
logger.info("New status: {}", newValue1));
|
||||
player.currentTimeProperty().addListener((ignored, oldTime, newTime) -> currentTimeChanged(oldTime.toMillis(), newTime.toMillis()));
|
||||
playSlider.setOnMousePressed(e -> {
|
||||
wasPlaying = model.isPlaying();
|
||||
model.setIsPlaying(false);
|
||||
});
|
||||
playSlider.valueProperty().addListener(observable1 -> {
|
||||
if (playSlider.isValueChanging()) {
|
||||
seek((long) playSlider.getValue());
|
||||
}
|
||||
});
|
||||
playSlider.setOnMouseReleased(e -> {
|
||||
final var value = playSlider.getValue();
|
||||
Platform.runLater(() -> {
|
||||
seek((long) value);
|
||||
model.setIsPlaying(wasPlaying);
|
||||
});
|
||||
});
|
||||
player.volumeProperty().bindBidirectional(model.volumeProperty());
|
||||
player.setOnPlaying(() -> model.setIsPlaying(true));
|
||||
player.setOnPaused(() -> model.setIsPlaying(false));
|
||||
player.setOnEndOfMedia(() -> model.setIsPlaying(false));
|
||||
playSlider.setMax(model.duration());
|
||||
playSlider.setValue(0L);
|
||||
videoView.setMediaPlayer(player);
|
||||
}
|
||||
|
||||
private void currentTimeChanged(final double oldMillis, final double millis) {
|
||||
playSlider.setValue(millis);
|
||||
final var subtitleLabels = stackPane.getChildren().stream().filter(SubtitleLabel.class::isInstance).map(SubtitleLabel.class::cast).toList();
|
||||
subtitleLabels.stream().filter(s -> !s.subtitle().isShowing((long) millis)).forEach(sl -> stackPane.getChildren().remove(sl));
|
||||
final var containedSubtitles = subtitleLabels.stream().map(SubtitleLabel::subtitle).filter(s -> s.isShowing((long) millis)).collect(Collectors.toSet());
|
||||
|
||||
model.subtitles().forEach(s -> {
|
||||
if (!containedSubtitles.contains(s)) {
|
||||
logger.info("Adding label {} at {}", s, millis);
|
||||
final var label = createDraggableLabel(s);
|
||||
stackPane.getChildren().add(label);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void currentTimeChangedOptimized(final double oldMillis, final double millis) {
|
||||
final var forward = oldMillis <= millis;
|
||||
|
||||
var index = Collections.binarySearch(startTimes, (long) millis);
|
||||
if (index < 0) {
|
||||
index = forward ? -(index + 1) : -(index + 2);
|
||||
}
|
||||
//TODO
|
||||
}
|
||||
|
||||
private void bindPlayButton() {
|
||||
playButton.disableProperty().bind(model.videoProperty().isNull());
|
||||
playButton.graphicProperty().bind(Bindings.createObjectBinding(() -> {
|
||||
final ImageView view;
|
||||
@@ -158,7 +196,6 @@ public class FXMediaController implements MediaController {
|
||||
view.setFitHeight(24);
|
||||
return view;
|
||||
}, model.isPlayingProperty()));
|
||||
binder.createBindings();
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
||||
@@ -6,10 +6,10 @@ import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* FX implementation of {@link com.github.gtache.autosubtitle.gui.MediaModel}
|
||||
@@ -22,7 +22,7 @@ public class FXMediaModel implements MediaModel {
|
||||
private final BooleanProperty isPlaying;
|
||||
private final ReadOnlyLongWrapper duration;
|
||||
private final LongProperty position;
|
||||
private final List<EditableSubtitle> subtitles;
|
||||
private final ObservableList<EditableSubtitle> subtitles;
|
||||
|
||||
@Inject
|
||||
FXMediaModel() {
|
||||
@@ -103,7 +103,7 @@ public class FXMediaModel implements MediaModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EditableSubtitle> subtitles() {
|
||||
public ObservableList<EditableSubtitle> subtitles() {
|
||||
return subtitles;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(FXWorkController.class);
|
||||
|
||||
private static final String ALL_SUPPORTED = "All supported";
|
||||
private static final List<String> VIDEO_EXTENSIONS = Stream.of("webm", "mkv", "flv", "vob", "ogv", "ogg",
|
||||
"drc", "gif", "gifv", "mng", "avi", "mts", "m2ts", "ts", "mov", "qt", "wmv", "yuv", "rm", "rmvb",
|
||||
"viv", "asf", "amv", "mp4", "m4p", "m4v", "mpg", "mp2", "mpeg", "mpe", "mpv", "m2v", "m4v", "svi",
|
||||
@@ -131,21 +132,42 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
|
||||
@FXML
|
||||
private void initialize() {
|
||||
bindComboboxes();
|
||||
bindButtons();
|
||||
bindTable();
|
||||
bindProgress();
|
||||
|
||||
model.selectedSubtitleProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
mediaController.seek(newValue.start());
|
||||
}
|
||||
});
|
||||
|
||||
binder.createBindings();
|
||||
|
||||
subtitleExtractor.addListener(this);
|
||||
}
|
||||
|
||||
private void bindComboboxes() {
|
||||
languageCombobox.valueProperty().bindBidirectional(model.videoLanguageProperty());
|
||||
languageCombobox.setItems(model.availableVideoLanguages());
|
||||
languageCombobox.setConverter(new LanguageStringConverter());
|
||||
translationsCombobox.setConverter(new LanguageStringConverter());
|
||||
Bindings.bindContent(translationsCombobox.getItems(), model.availableTranslationsLanguage());
|
||||
Bindings.bindContent(model.translations(), translationsCombobox.getCheckModel().getCheckedItems());
|
||||
}
|
||||
|
||||
private void bindButtons() {
|
||||
extractButton.disableProperty().bind(model.videoProperty().isNull().or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
addSubtitleButton.disableProperty().bind(model.videoProperty().isNull().or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
loadSubtitlesButton.disableProperty().bind(model.videoProperty().isNull().or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
resetButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()).or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
exportSoftButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()).or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
exportHardButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()).or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
addSubtitleButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()).or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
loadSubtitlesButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()).or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
saveSubtitlesButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()).or(model.statusProperty().isNotEqualTo(WorkStatus.IDLE)));
|
||||
}
|
||||
|
||||
private void bindTable() {
|
||||
subtitlesTable.setItems(model.subtitles());
|
||||
subtitlesTable.setOnKeyPressed(e -> {
|
||||
if (e.getCode().isLetterKey() || e.getCode().isDigitKey()) {
|
||||
@@ -157,6 +179,9 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
} else if (e.getCode() == KeyCode.LEFT) {
|
||||
subtitlesTable.getSelectionModel().selectPrevious();
|
||||
e.consume();
|
||||
} else if (e.getCode() == KeyCode.DELETE) {
|
||||
deleteSelectedSubtitles();
|
||||
e.consume();
|
||||
}
|
||||
});
|
||||
startColumn.setCellFactory(TextFieldTableCell.forTableColumn(new TimeStringConverter(timeFormatter)));
|
||||
@@ -185,11 +210,9 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
});
|
||||
|
||||
subtitlesTable.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> model.selectedSubtitleProperty().set(newValue));
|
||||
model.selectedSubtitleProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
mediaController.seek(newValue.start());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void bindProgress() {
|
||||
progressLabel.textProperty().bind(Bindings.createStringBinding(() -> resources.getString("work.status." + model.status().name().toLowerCase() + ".label"), model.statusProperty()));
|
||||
progressLabel.visibleProperty().bind(model.statusProperty().isNotEqualTo(WorkStatus.IDLE));
|
||||
progressBar.visibleProperty().bind(model.statusProperty().isNotEqualTo(WorkStatus.IDLE));
|
||||
@@ -198,9 +221,10 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
progressBar.managedProperty().bind(model.statusProperty().isNotEqualTo(WorkStatus.IDLE));
|
||||
progressDetailLabel.managedProperty().bind(model.statusProperty().isNotEqualTo(WorkStatus.IDLE));
|
||||
progressBar.progressProperty().bindBidirectional(model.progressProperty());
|
||||
binder.createBindings();
|
||||
}
|
||||
|
||||
subtitleExtractor.addListener(this);
|
||||
private void deleteSelectedSubtitles() {
|
||||
model.subtitles().removeAll(subtitlesTable.getSelectionModel().getSelectedItems());
|
||||
}
|
||||
|
||||
private void editFocusedCell() {
|
||||
@@ -213,7 +237,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
@FXML
|
||||
private void fileButtonPressed() {
|
||||
final var filePicker = new FileChooser();
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter("All supported", VIDEO_EXTENSIONS);
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter(ALL_SUPPORTED, VIDEO_EXTENSIONS);
|
||||
filePicker.getExtensionFilters().add(extensionFilter);
|
||||
filePicker.setSelectedExtensionFilter(extensionFilter);
|
||||
final var file = filePicker.showOpenDialog(window());
|
||||
@@ -303,6 +327,9 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
@FXML
|
||||
private void exportSoftPressed() {
|
||||
final var filePicker = new FileChooser();
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter(ALL_SUPPORTED, VIDEO_EXTENSIONS);
|
||||
filePicker.getExtensionFilters().add(extensionFilter);
|
||||
filePicker.setSelectedExtensionFilter(extensionFilter);
|
||||
final var file = filePicker.showSaveDialog(window());
|
||||
if (file != null) {
|
||||
final var baseCollection = model.subtitleCollection();
|
||||
@@ -315,7 +342,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
}, Platform::runLater)
|
||||
.thenAcceptAsync(collections -> {
|
||||
try {
|
||||
videoConverter.addSoftSubtitles(model.video(), collections);
|
||||
videoConverter.addSoftSubtitles(model.video(), collections, file.toPath());
|
||||
} catch (final IOException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@@ -332,11 +359,14 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
@FXML
|
||||
private void exportHardPressed() {
|
||||
final var filePicker = new FileChooser();
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter(ALL_SUPPORTED, VIDEO_EXTENSIONS);
|
||||
filePicker.getExtensionFilters().add(extensionFilter);
|
||||
filePicker.setSelectedExtensionFilter(extensionFilter);
|
||||
final var file = filePicker.showSaveDialog(window());
|
||||
if (file != null) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
videoConverter.addHardSubtitles(model.video(), model.subtitleCollection());
|
||||
videoConverter.addHardSubtitles(model.video(), model.subtitleCollection(), file.toPath());
|
||||
} catch (final IOException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@@ -386,7 +416,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
@FXML
|
||||
private void loadSubtitlesPressed() {
|
||||
final var filePicker = new FileChooser();
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter("All supported", subtitleExtensions);
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter(ALL_SUPPORTED, subtitleExtensions);
|
||||
filePicker.getExtensionFilters().add(extensionFilter);
|
||||
filePicker.setSelectedExtensionFilter(extensionFilter);
|
||||
final var file = filePicker.showOpenDialog(window());
|
||||
@@ -396,7 +426,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
|
||||
@FXML
|
||||
private void saveSubtitlesPressed() {
|
||||
final var filePicker = new FileChooser();
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter("All supported", subtitleExtensions);
|
||||
final var extensionFilter = new FileChooser.ExtensionFilter(ALL_SUPPORTED, subtitleExtensions);
|
||||
filePicker.getExtensionFilters().add(extensionFilter);
|
||||
filePicker.setSelectedExtensionFilter(extensionFilter);
|
||||
final var file = filePicker.showSaveDialog(window());
|
||||
|
||||
@@ -75,12 +75,11 @@ public class FXWorkModel implements WorkModel {
|
||||
this.extractionModel = new SimpleObjectProperty<>();
|
||||
this.progress = new SimpleDoubleProperty(-1);
|
||||
text.bind(Bindings.createStringBinding(() ->
|
||||
subtitles.stream().map(EditableSubtitle::content).collect(Collectors.joining(" ")),
|
||||
subtitles.stream().map(EditableSubtitle::content).collect(Collectors.joining("")),
|
||||
subtitles));
|
||||
subtitleCollection.bind(Bindings.createObjectBinding(() -> new SubtitleCollectionImpl(text(), subtitles, videoLanguage())));
|
||||
videoLanguage.addListener((observable, oldValue, newValue) -> {
|
||||
FXCollections.observableArrayList(Arrays.stream(Language.values()).filter(l -> l != Language.AUTO && l != newValue).sorted(Comparator.naturalOrder()).toList());
|
||||
});
|
||||
subtitleCollection.bind(Bindings.createObjectBinding(() -> new SubtitleCollectionImpl(text(), subtitles, videoLanguage()), text, subtitles, videoLanguage));
|
||||
videoLanguage.addListener((observable, oldValue, newValue) -> FXCollections.observableArrayList(Arrays.stream(Language.values())
|
||||
.filter(l -> l != Language.AUTO && l != newValue).sorted(Comparator.naturalOrder()).toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -54,14 +54,12 @@ public abstract class FXModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Play
|
||||
static Image providesPlayImage(@Play final byte[] playImage) {
|
||||
return new Image(new ByteArrayInputStream(playImage));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Pause
|
||||
static Image providesPauseImage(@Pause final byte[] pauseImage) {
|
||||
return new Image(new ByteArrayInputStream(pauseImage));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* FX module for auto-subtitle
|
||||
*/
|
||||
module com.github.gtache.autosubtitle.fx {
|
||||
module com.github.gtache.autosubtitle.gui.fx {
|
||||
requires transitive com.github.gtache.autosubtitle.core;
|
||||
requires transitive com.github.gtache.autosubtitle.gui.core;
|
||||
requires transitive javafx.controls;
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ProgressBar?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import org.controlsfx.control.CheckComboBox?>
|
||||
<?import org.controlsfx.control.PrefixSelectionComboBox?>
|
||||
<GridPane hgap="10.0" vgap="10.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="com.github.gtache.autosubtitle.gui.fx.FXWorkController">
|
||||
|
||||
<GridPane hgap="10.0" vgap="10.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.github.gtache.autosubtitle.gui.fx.FXWorkController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES"/>
|
||||
<ColumnConstraints hgrow="ALWAYS"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES" />
|
||||
<ColumnConstraints hgrow="ALWAYS" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
<RowConstraints vgrow="ALWAYS"/>
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
<RowConstraints vgrow="NEVER"/>
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="ALWAYS" />
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="NEVER" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<TextField fx:id="fileField" editable="false" GridPane.columnIndex="1"/>
|
||||
<Button mnemonicParsing="false" onAction="#fileButtonPressed" text="%work.button.file.label"
|
||||
GridPane.columnIndex="2"/>
|
||||
<TextField fx:id="fileField" editable="false" GridPane.columnIndex="1" />
|
||||
<Button mnemonicParsing="false" onAction="#fileButtonPressed" text="%work.button.file.label" GridPane.columnIndex="2" />
|
||||
<HBox spacing="10.0" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Button fx:id="loadSubtitlesButton" mnemonicParsing="false" onAction="#loadSubtitlesPressed"
|
||||
text="%work.button.load.label"/>
|
||||
<Button fx:id="extractButton" mnemonicParsing="false" onAction="#extractPressed"
|
||||
text="%work.button.extract.label"/>
|
||||
<Button fx:id="extractButton" mnemonicParsing="false" onAction="#extractPressed" text="%work.button.extract.label" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_RIGHT" spacing="10.0" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Button fx:id="exportSoftButton" mnemonicParsing="false" onAction="#exportSoftPressed"
|
||||
text="%work.button.export.soft.label">
|
||||
<Button fx:id="exportSoftButton" mnemonicParsing="false" onAction="#exportSoftPressed" text="%work.button.export.soft.label">
|
||||
<tooltip>
|
||||
<Tooltip text="%work.button.export.soft.tooltip"/>
|
||||
<Tooltip text="%work.button.export.soft.tooltip" />
|
||||
</tooltip>
|
||||
</Button>
|
||||
<Button fx:id="exportHardButton" mnemonicParsing="false" onAction="#exportHardPressed"
|
||||
text="%work.button.export.hard.label">
|
||||
<Button fx:id="exportHardButton" mnemonicParsing="false" onAction="#exportHardPressed" text="%work.button.export.hard.label">
|
||||
<tooltip>
|
||||
<Tooltip text="%work.button.export.hard.tooltip"/>
|
||||
<Tooltip text="%work.button.export.hard.tooltip" />
|
||||
</tooltip>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
<TableView fx:id="subtitlesTable" editable="true" GridPane.rowIndex="1">
|
||||
<columns>
|
||||
<TableColumn fx:id="startColumn" prefWidth="50.0" sortable="false"
|
||||
text="%work.table.column.from.label"/>
|
||||
<TableColumn fx:id="endColumn" prefWidth="50.0" sortable="false" text="%work.table.column.to.label"/>
|
||||
<TableColumn fx:id="textColumn" prefWidth="75.0" sortable="false" text="%work.table.column.text.label"/>
|
||||
<TableColumn fx:id="startColumn" prefWidth="50.0" sortable="false" text="%work.table.column.from.label" />
|
||||
<TableColumn fx:id="endColumn" prefWidth="50.0" sortable="false" text="%work.table.column.to.label" />
|
||||
<TableColumn fx:id="textColumn" prefWidth="75.0" sortable="false" text="%work.table.column.text.label" />
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TableView>
|
||||
<HBox spacing="10.0" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Button fx:id="resetButton" mnemonicParsing="false" onAction="#resetButtonPressed"
|
||||
text="%work.button.reset.label"/>
|
||||
<Button fx:id="saveSubtitlesButton" mnemonicParsing="false" onAction="#saveSubtitlesPressed"
|
||||
text="%work.button.subtitles.save.label"/>
|
||||
<Button fx:id="addSubtitleButton" mnemonicParsing="false" onAction="#addSubtitlePressed" text="+"/>
|
||||
<Button fx:id="loadSubtitlesButton" mnemonicParsing="false" onAction="#loadSubtitlesPressed" text="%work.button.load.label" />
|
||||
<Button fx:id="saveSubtitlesButton" mnemonicParsing="false" onAction="#saveSubtitlesPressed" text="%work.button.subtitles.save.label" />
|
||||
<Button fx:id="resetButton" mnemonicParsing="false" onAction="#resetButtonPressed" text="%work.button.reset.label" />
|
||||
<Button fx:id="addSubtitleButton" mnemonicParsing="false" onAction="#addSubtitlePressed" text="+" />
|
||||
</children>
|
||||
<GridPane.margin>
|
||||
<Insets/>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
</HBox>
|
||||
<fx:include fx:id="media" source="mediaView.fxml" GridPane.columnIndex="1" GridPane.columnSpan="2147483647"
|
||||
GridPane.rowIndex="1"/>
|
||||
<fx:include fx:id="media" source="mediaView.fxml" GridPane.columnIndex="1" GridPane.columnSpan="2147483647" GridPane.rowIndex="1" />
|
||||
<HBox alignment="CENTER_LEFT" spacing="10.0">
|
||||
<children>
|
||||
<Label text="%work.language.label"/>
|
||||
<PrefixSelectionComboBox fx:id="languageCombobox"/>
|
||||
<Label text="%work.translate.label"/>
|
||||
<CheckComboBox fx:id="translationsCombobox"/>
|
||||
<Label text="%work.language.label" />
|
||||
<PrefixSelectionComboBox fx:id="languageCombobox" />
|
||||
<Label text="%work.translate.label" />
|
||||
<CheckComboBox fx:id="translationsCombobox" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Label fx:id="progressLabel" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
|
||||
<Label fx:id="progressLabel" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<HBox spacing="10.0" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label fx:id="progressDetailLabel"/>
|
||||
<ProgressBar fx:id="progressBar" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS"/>
|
||||
<Label fx:id="progressDetailLabel" />
|
||||
<ProgressBar fx:id="progressBar" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
<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" />
|
||||
</padding>
|
||||
</GridPane>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gtache.autosubtitle</groupId>
|
||||
<artifactId>autosubtitle-fx</artifactId>
|
||||
<artifactId>autosubtitle-gui-fx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gtache.autosubtitle</groupId>
|
||||
<artifactId>autosubtitle-fx</artifactId>
|
||||
<artifactId>autosubtitle-gui-fx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gtache.autosubtitle</groupId>
|
||||
|
||||
@@ -17,6 +17,10 @@ import javax.inject.Singleton;
|
||||
@Module
|
||||
public abstract class MissingComponentsModule {
|
||||
|
||||
private MissingComponentsModule() {
|
||||
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Translator providesTranslator() {
|
||||
|
||||
@@ -4,9 +4,6 @@ import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegModule;
|
||||
import com.github.gtache.autosubtitle.modules.gui.fx.FXModule;
|
||||
import com.github.gtache.autosubtitle.modules.gui.impl.GuiCoreModule;
|
||||
import com.github.gtache.autosubtitle.modules.impl.CoreModule;
|
||||
import com.github.gtache.autosubtitle.modules.setup.ffmpeg.FFmpegSetupModule;
|
||||
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperSetupModule;
|
||||
import com.github.gtache.autosubtitle.modules.subtitle.impl.SubtitleModule;
|
||||
import com.github.gtache.autosubtitle.modules.whisper.WhisperModule;
|
||||
import dagger.Component;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@@ -17,8 +14,8 @@ import javax.inject.Singleton;
|
||||
* Main component
|
||||
*/
|
||||
@Singleton
|
||||
@Component(modules = {CoreModule.class, GuiCoreModule.class, FXModule.class, FFmpegModule.class, FFmpegSetupModule.class,
|
||||
SubtitleModule.class, WhisperModule.class, WhisperSetupModule.class, MissingComponentsModule.class})
|
||||
@Component(modules = {CoreModule.class, GuiCoreModule.class, FXModule.class, FFmpegModule.class,
|
||||
WhisperModule.class, MissingComponentsModule.class})
|
||||
public interface RunComponent {
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
module com.github.gtache.autosubtitle.run {
|
||||
requires com.github.gtache.autosubtitle.ffmpeg;
|
||||
requires com.github.gtache.autosubtitle.fx;
|
||||
requires com.github.gtache.autosubtitle.gui.fx;
|
||||
requires com.github.gtache.autosubtitle.whisper;
|
||||
|
||||
opens com.github.gtache.autosubtitle.run to javafx.graphics;
|
||||
|
||||
Reference in New Issue
Block a user