diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index 6b5c9e1..412d5ee 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -5,12 +5,16 @@
+
+
+
+
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/Translator.java b/api/src/main/java/com/github/gtache/autosubtitle/Translator.java
index b80965a..0cee55c 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/Translator.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/Translator.java
@@ -1,20 +1,90 @@
package com.github.gtache.autosubtitle;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
+import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import java.util.Locale;
+/**
+ * Translates texts and subtitles
+ */
public interface Translator {
+ /**
+ * Guesses the locale of the given text
+ *
+ * @param text The text
+ * @return The guessed locale
+ */
+ Locale getLocale(final String text);
+
+ /**
+ * Guesses the locale of the given subtitle
+ *
+ * @param subtitle The subtitle
+ * @return The guessed locale
+ */
+ default Locale getLocale(final Subtitle subtitle) {
+ return getLocale(subtitle.content());
+ }
+
+ /**
+ * Translates the given text to the given locale
+ *
+ * @param text The text to translate
+ * @param to The target locale
+ * @return The translated text
+ */
String translate(String text, Locale to);
+ /**
+ * Translates the given text to the given locale
+ *
+ * @param text The text to translate
+ * @param to The target locale
+ * @return The translated text
+ */
default String translate(final String text, final String to) {
return translate(text, Locale.forLanguageTag(to));
}
+ /**
+ * Translates the given subtitle to the given locale
+ *
+ * @param subtitle The subtitle to translate
+ * @param to The target locale
+ * @return The translated subtitle
+ */
Subtitle translate(Subtitle subtitle, Locale to);
+ /**
+ * Translates the given subtitle to the given locale
+ *
+ * @param subtitle The subtitle to translate
+ * @param to The target locale
+ * @return The translated subtitle
+ */
default Subtitle translate(final Subtitle subtitle, final String to) {
return translate(subtitle, Locale.forLanguageTag(to));
}
+
+ /**
+ * Translates the given subtitles collection to the given locale
+ *
+ * @param collection The subtitles collection to translate
+ * @param to The target locale
+ * @return The translated subtitles collection
+ */
+ default SubtitleCollection translate(final SubtitleCollection collection, final String to) {
+ return translate(collection, Locale.forLanguageTag(to));
+ }
+
+ /**
+ * Translates the given subtitles collection to the given locale
+ *
+ * @param collection The subtitles collection to translate
+ * @param to The target locale
+ * @return The translated subtitles collection
+ */
+ SubtitleCollection translate(SubtitleCollection collection, Locale to);
}
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/Video.java b/api/src/main/java/com/github/gtache/autosubtitle/Video.java
index d3a56e9..e929912 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/Video.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/Video.java
@@ -18,4 +18,5 @@ public interface Video {
* @return The video info
*/
VideoInfo info();
+
}
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/VideoInfo.java b/api/src/main/java/com/github/gtache/autosubtitle/VideoInfo.java
index b2e940b..d557606 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/VideoInfo.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/VideoInfo.java
@@ -8,4 +8,27 @@ public interface VideoInfo {
* @return The video extension (mp4, etc.)
*/
String videoFormat();
+
+ /**
+ * @return The video width in pixels
+ */
+ int width();
+
+ /**
+ * @return The video height in pixels
+ */
+ int height();
+
+
+ /**
+ * @return The video duration in milliseconds
+ */
+ long duration();
+
+ /**
+ * @return The aspect ratio of the video
+ */
+ default double aspectRatio() {
+ return (double) width() / height();
+ }
}
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/VideoLoader.java b/api/src/main/java/com/github/gtache/autosubtitle/VideoLoader.java
new file mode 100644
index 0000000..6fd0bc7
--- /dev/null
+++ b/api/src/main/java/com/github/gtache/autosubtitle/VideoLoader.java
@@ -0,0 +1,20 @@
+package com.github.gtache.autosubtitle;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * Loads videos
+ */
+@FunctionalInterface
+public interface VideoLoader {
+
+ /**
+ * Loads a video
+ *
+ * @param path The path to the video
+ * @return The loaded video
+ * @throws IOException If an error occurred
+ */
+ Video loadVideo(final Path path) throws IOException;
+}
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupException.java b/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupException.java
index f6e7236..b3b9e3f 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupException.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupException.java
@@ -1,5 +1,8 @@
package com.github.gtache.autosubtitle.setup;
+/**
+ * Exception thrown when an error occurs during setup
+ */
public class SetupException extends Exception {
public SetupException(final String message) {
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupManager.java b/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupManager.java
index da4e4de..b95c0c0 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupManager.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupManager.java
@@ -20,7 +20,7 @@ public interface SetupManager {
* @throws SetupException if an error occurred during the check
*/
default boolean isInstalled() throws SetupException {
- return status() != SetupStatus.NOT_INSTALLED;
+ return status().isInstalled();
}
/**
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupStatus.java b/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupStatus.java
index 2be94e7..15fbbcb 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupStatus.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/setup/SetupStatus.java
@@ -4,5 +4,9 @@ package com.github.gtache.autosubtitle.setup;
* The status of a setup
*/
public enum SetupStatus {
- NOT_INSTALLED, INSTALLED, UPDATE_AVAILABLE
+ ERRORED, NOT_INSTALLED, INSTALLED, UPDATE_AVAILABLE;
+
+ public boolean isInstalled() {
+ return this == INSTALLED || this == UPDATE_AVAILABLE;
+ }
}
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleCollection.java b/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleCollection.java
index cc6232b..0b0a053 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleCollection.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleCollection.java
@@ -1,6 +1,7 @@
package com.github.gtache.autosubtitle.subtitle;
import java.util.Collection;
+import java.util.Locale;
/**
* Represents a collection of {@link Subtitle}
@@ -13,7 +14,7 @@ public interface SubtitleCollection {
Collection extends Subtitle> subtitles();
/**
- * @return The language of the subtitles
+ * @return The locale of the subtitles
*/
- String language();
+ Locale locale();
}
diff --git a/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleExtractor.java b/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleExtractor.java
index b64a532..08c006b 100644
--- a/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleExtractor.java
+++ b/api/src/main/java/com/github/gtache/autosubtitle/subtitle/SubtitleExtractor.java
@@ -10,7 +10,7 @@ import java.util.Collection;
*/
public interface SubtitleExtractor {
- Collection extract(final Video in);
+ Collection extends EditableSubtitle> extract(final Video in);
- Collection extract(final Audio in);
+ Collection extends EditableSubtitle> extract(final Audio in);
}
diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java
new file mode 100644
index 0000000..6a7fe34
--- /dev/null
+++ b/api/src/main/java/module-info.java
@@ -0,0 +1,9 @@
+/**
+ * API module for auto-subtitle
+ */
+module com.github.gtache.autosubtitle.api {
+ exports com.github.gtache.autosubtitle;
+ exports com.github.gtache.autosubtitle.process;
+ exports com.github.gtache.autosubtitle.setup;
+ exports com.github.gtache.autosubtitle.subtitle;
+}
\ No newline at end of file
diff --git a/core/pom.xml b/core/pom.xml
index 87987b4..ee2e5d0 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -23,7 +23,6 @@
org.apache.logging.log4j
log4j-api
- 2.23.1
\ No newline at end of file
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/impl/Architecture.java b/core/src/main/java/com/github/gtache/autosubtitle/impl/Architecture.java
new file mode 100644
index 0000000..c41accb
--- /dev/null
+++ b/core/src/main/java/com/github/gtache/autosubtitle/impl/Architecture.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.impl;
+
+/**
+ * The list of possible operating systems
+ */
+public enum Architecture {
+ I386, I486, I586, I686, PPC, POWERPC, X86, X86_32, X86_64, AMD64, ARM, ARM32, ARM64, AARCH64, UNKNOWN;
+
+ public static Architecture getArchitecture(final String name) {
+ try {
+ return valueOf(name.toUpperCase());
+ } catch (final IllegalArgumentException e) {
+ return UNKNOWN;
+ }
+ }
+}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/impl/OS.java b/core/src/main/java/com/github/gtache/autosubtitle/impl/OS.java
new file mode 100644
index 0000000..6a8d6b7
--- /dev/null
+++ b/core/src/main/java/com/github/gtache/autosubtitle/impl/OS.java
@@ -0,0 +1,8 @@
+package com.github.gtache.autosubtitle.impl;
+
+/**
+ * The list of possible operating systems
+ */
+public enum OS {
+ WINDOWS, LINUX, MAC
+}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/impl/VideoInfoImpl.java b/core/src/main/java/com/github/gtache/autosubtitle/impl/VideoInfoImpl.java
index 99deb0b..051ef21 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/impl/VideoInfoImpl.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/impl/VideoInfoImpl.java
@@ -7,10 +7,19 @@ import java.util.Objects;
/**
* Implementation of {@link VideoInfo}
*/
-public record VideoInfoImpl(String videoFormat) implements VideoInfo {
+public record VideoInfoImpl(String videoFormat, int width, int height, long duration) implements VideoInfo {
public VideoInfoImpl {
Objects.requireNonNull(videoFormat);
+ if (width <= 0) {
+ throw new IllegalArgumentException("Width must be greater than 0 : " + width);
+ }
+ if (height <= 0) {
+ throw new IllegalArgumentException("Height must be greater than 0 : " + height);
+ }
+ if (duration <= 0) {
+ throw new IllegalArgumentException("Duration must be greater than 0 : " + duration);
+ }
}
@Override
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/modules/impl/CoreModule.java b/core/src/main/java/com/github/gtache/autosubtitle/modules/impl/CoreModule.java
new file mode 100644
index 0000000..96b6728
--- /dev/null
+++ b/core/src/main/java/com/github/gtache/autosubtitle/modules/impl/CoreModule.java
@@ -0,0 +1,39 @@
+package com.github.gtache.autosubtitle.modules.impl;
+
+import com.github.gtache.autosubtitle.impl.Architecture;
+import com.github.gtache.autosubtitle.impl.OS;
+import dagger.Module;
+import dagger.Provides;
+
+import javax.inject.Singleton;
+
+@Module
+public abstract class CoreModule {
+
+ @Provides
+ @Singleton
+ static OS providesOS() {
+ final var name = System.getProperty("os.name");
+ if (name.contains("Windows")) {
+ return OS.WINDOWS;
+ } else if (name.contains("Mac")) {
+ return OS.MAC;
+ } else {
+ return OS.LINUX;
+ }
+ }
+
+ @Provides
+ @Singleton
+ static Architecture providesArchitecture() {
+ final var arch = System.getProperty("os.arch");
+ return Architecture.getArchitecture(arch);
+ }
+
+ @Provides
+ @Singleton
+ @ExecutableExtension
+ static String providesExecutableExtension(final OS os) {
+ return os == OS.WINDOWS ? ".exe" : "";
+ }
+}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/modules/impl/ExecutableExtension.java b/core/src/main/java/com/github/gtache/autosubtitle/modules/impl/ExecutableExtension.java
new file mode 100644
index 0000000..0a29dfd
--- /dev/null
+++ b/core/src/main/java/com/github/gtache/autosubtitle/modules/impl/ExecutableExtension.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.impl;
+
+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 ExecutableExtension {
+}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/process/impl/AbstractProcessRunner.java b/core/src/main/java/com/github/gtache/autosubtitle/process/impl/AbstractProcessRunner.java
index a0e4a1e..dd87c23 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/process/impl/AbstractProcessRunner.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/process/impl/AbstractProcessRunner.java
@@ -12,6 +12,7 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
@@ -24,25 +25,28 @@ public abstract class AbstractProcessRunner implements ProcessRunner {
@Override
public ProcessResult run(final List args) throws IOException {
final var builder = new ProcessBuilder(args);
- builder.inheritIO();
builder.redirectErrorStream(true);
final var process = builder.start();
- final var output = new ArrayList();
- new Thread(() -> {
+ final var readFuture = CompletableFuture.supplyAsync(() -> {
+ final var output = new ArrayList();
try (final var in = new BufferedReader(new InputStreamReader(new BufferedInputStream(process.getInputStream()), StandardCharsets.UTF_8))) {
- while (in.ready()) {
- output.add(in.readLine());
+ var line = in.readLine();
+ while (line != null) {
+ output.add(line);
+ line = in.readLine();
}
} catch (final IOException e) {
logger.error("Error listening to process output of {}", args, e);
}
- }).start();
+ return output;
+ });
try {
process.waitFor(1, TimeUnit.HOURS);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
process.destroy();
}
+ final var output = readFuture.join();
return new ProcessResultImpl(process.exitValue(), output);
}
}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/VideoConverter.java b/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/SubtitleExtractorSetup.java
similarity index 75%
rename from core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/VideoConverter.java
rename to core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/SubtitleExtractorSetup.java
index d23a279..bff9369 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/VideoConverter.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/SubtitleExtractorSetup.java
@@ -11,6 +11,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
-@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.FIELD})
-public @interface VideoConverter {
+@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
+public @interface SubtitleExtractorSetup {
}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/Translator.java b/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/TranslatorSetup.java
similarity index 76%
rename from core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/Translator.java
rename to core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/TranslatorSetup.java
index 32b4c64..8a45dc6 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/Translator.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/TranslatorSetup.java
@@ -11,6 +11,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
-@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.FIELD})
-public @interface Translator {
+@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
+public @interface TranslatorSetup {
}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/SubtitleExtractor.java b/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/VideoConverterSetup.java
similarity index 75%
rename from core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/SubtitleExtractor.java
rename to core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/VideoConverterSetup.java
index 831400e..58f65e3 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/SubtitleExtractor.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/setup/modules/impl/VideoConverterSetup.java
@@ -11,6 +11,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
-@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.FIELD})
-public @interface SubtitleExtractor {
+@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
+public @interface VideoConverterSetup {
}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SRTSubtitleConverter.java b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SRTSubtitleConverter.java
index a599d69..d370ebd 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SRTSubtitleConverter.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SRTSubtitleConverter.java
@@ -3,13 +3,21 @@ package com.github.gtache.autosubtitle.subtitle.impl;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.SubtitleConverter;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* Converts subtitles to SRT format
*/
+@Singleton
public class SRTSubtitleConverter implements SubtitleConverter {
- public String convert(final SubtitleCollection collection) {
+ @Inject
+ SRTSubtitleConverter() {
+ }
+ public String convert(final SubtitleCollection collection) {
+ throw new UnsupportedOperationException("TODO");
}
@Override
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleCollectionImpl.java b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleCollectionImpl.java
index 7295046..f021551 100644
--- a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleCollectionImpl.java
+++ b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleCollectionImpl.java
@@ -5,6 +5,7 @@ import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import java.util.Collection;
import java.util.List;
+import java.util.Locale;
import static java.util.Objects.requireNonNull;
@@ -12,10 +13,10 @@ import static java.util.Objects.requireNonNull;
* Implementation of {@link SubtitleCollection}
*/
public record SubtitleCollectionImpl(Collection extends Subtitle> subtitles,
- String language) implements SubtitleCollection {
+ Locale locale) implements SubtitleCollection {
public SubtitleCollectionImpl {
subtitles = List.copyOf(subtitles);
- requireNonNull(language);
+ requireNonNull(locale);
}
}
diff --git a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/modules/impl/ConverterModule.java b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/modules/impl/ConverterModule.java
new file mode 100644
index 0000000..4b913c0
--- /dev/null
+++ b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/modules/impl/ConverterModule.java
@@ -0,0 +1,19 @@
+package com.github.gtache.autosubtitle.subtitle.modules.impl;
+
+import com.github.gtache.autosubtitle.subtitle.SubtitleConverter;
+import com.github.gtache.autosubtitle.subtitle.impl.SRTSubtitleConverter;
+import dagger.Binds;
+import dagger.Module;
+
+import javax.inject.Singleton;
+
+/**
+ * Dagger module for subtitle converter
+ */
+@Module
+public interface ConverterModule {
+
+ @Binds
+ @Singleton
+ SubtitleConverter bindsSubtitleConverter(final SRTSubtitleConverter converter);
+}
diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java
new file mode 100644
index 0000000..d42c585
--- /dev/null
+++ b/core/src/main/java/module-info.java
@@ -0,0 +1,16 @@
+/**
+ * Core module for auto-subtitle
+ */
+module com.github.gtache.autosubtitle.core {
+ requires transitive com.github.gtache.autosubtitle.api;
+ requires transitive dagger;
+ requires transitive javax.inject;
+ requires org.apache.logging.log4j;
+
+ exports com.github.gtache.autosubtitle.impl;
+ exports com.github.gtache.autosubtitle.modules.impl;
+ exports com.github.gtache.autosubtitle.process.impl;
+ exports com.github.gtache.autosubtitle.subtitle.impl;
+ exports com.github.gtache.autosubtitle.setup.modules.impl;
+ exports com.github.gtache.autosubtitle.subtitle.modules.impl;
+}
\ No newline at end of file
diff --git a/deepl/pom.xml b/deepl/pom.xml
new file mode 100644
index 0000000..0afc18f
--- /dev/null
+++ b/deepl/pom.xml
@@ -0,0 +1,21 @@
+
+
+ 4.0.0
+
+ com.github.gtache.autosubtitle
+ autosubtitle
+ 1.0-SNAPSHOT
+
+
+ autosubtitle-deepl
+
+
+
+
+ com.github.gtache.autosubtitle
+ autosubtitle-core
+
+
+
\ No newline at end of file
diff --git a/deepl/src/main/java/com/github/gtache/autosubtitle/deepl/DeepLTranslator.java b/deepl/src/main/java/com/github/gtache/autosubtitle/deepl/DeepLTranslator.java
new file mode 100644
index 0000000..17cdaaa
--- /dev/null
+++ b/deepl/src/main/java/com/github/gtache/autosubtitle/deepl/DeepLTranslator.java
@@ -0,0 +1,38 @@
+package com.github.gtache.autosubtitle.deepl;
+
+import com.github.gtache.autosubtitle.Translator;
+import com.github.gtache.autosubtitle.subtitle.Subtitle;
+import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
+
+import javax.inject.Inject;
+import java.util.Locale;
+
+/**
+ * DeepL implementation of {@link Translator}
+ */
+public class DeepLTranslator implements Translator {
+
+ @Inject
+ DeepLTranslator() {
+ }
+
+ @Override
+ public Locale getLocale(final String text) {
+ return null;
+ }
+
+ @Override
+ public String translate(final String text, final Locale to) {
+ return "";
+ }
+
+ @Override
+ public Subtitle translate(final Subtitle subtitle, final Locale to) {
+ return null;
+ }
+
+ @Override
+ public SubtitleCollection translate(final SubtitleCollection collection, final Locale to) {
+ return null;
+ }
+}
diff --git a/deepl/src/main/java/com/github/gtache/autosubtitle/modules/deepl/DeepLModule.java b/deepl/src/main/java/com/github/gtache/autosubtitle/modules/deepl/DeepLModule.java
new file mode 100644
index 0000000..801ed67
--- /dev/null
+++ b/deepl/src/main/java/com/github/gtache/autosubtitle/modules/deepl/DeepLModule.java
@@ -0,0 +1,19 @@
+package com.github.gtache.autosubtitle.modules.deepl;
+
+import com.github.gtache.autosubtitle.Translator;
+import com.github.gtache.autosubtitle.deepl.DeepLTranslator;
+import dagger.Binds;
+import dagger.Module;
+
+import javax.inject.Singleton;
+
+/**
+ * Dagger module for DeepL
+ */
+@Module
+public interface DeepLModule {
+
+ @Binds
+ @Singleton
+ Translator bindsTranslator(final DeepLTranslator translator);
+}
diff --git a/deepl/src/main/java/module-info.java b/deepl/src/main/java/module-info.java
new file mode 100644
index 0000000..0ea7396
--- /dev/null
+++ b/deepl/src/main/java/module-info.java
@@ -0,0 +1,8 @@
+/**
+ * DeepL module for auto-subtitle
+ */
+module com.github.gtache.autosubtitle.deepl {
+ requires transitive com.github.gtache.autosubtitle.core;
+ exports com.github.gtache.autosubtitle.deepl;
+ exports com.github.gtache.autosubtitle.modules.deepl;
+}
\ No newline at end of file
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFmpegVideoConverter.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFmpegVideoConverter.java
index baf8a9d..abd2ec9 100644
--- a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFmpegVideoConverter.java
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFmpegVideoConverter.java
@@ -8,20 +8,22 @@ import com.github.gtache.autosubtitle.impl.AudioInfoImpl;
import com.github.gtache.autosubtitle.impl.FileAudioImpl;
import com.github.gtache.autosubtitle.impl.FileVideoImpl;
import com.github.gtache.autosubtitle.impl.VideoInfoImpl;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegBundledPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegSystemPath;
+import com.github.gtache.autosubtitle.process.impl.AbstractProcessRunner;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.SubtitleConverter;
import javax.inject.Inject;
+import javax.inject.Singleton;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.SequencedMap;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Objects.requireNonNull;
@@ -29,15 +31,18 @@ import static java.util.Objects.requireNonNull;
/**
* FFmpeg implementation of {@link VideoConverter}
*/
-public class FFmpegVideoConverter implements VideoConverter {
+@Singleton
+public class FFmpegVideoConverter extends AbstractProcessRunner implements VideoConverter {
private static final String TEMP_FILE_PREFIX = "autosubtitle";
- private final Path ffmpegPath;
+ private final Path bundledPath;
+ private final Path systemPath;
private final SubtitleConverter subtitleConverter;
@Inject
- FFmpegVideoConverter(final Path ffmpegPath, final SubtitleConverter subtitleConverter) {
- this.ffmpegPath = requireNonNull(ffmpegPath);
+ FFmpegVideoConverter(@FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath, final SubtitleConverter subtitleConverter) {
+ this.bundledPath = requireNonNull(bundledPath);
+ this.systemPath = requireNonNull(systemPath);
this.subtitleConverter = requireNonNull(subtitleConverter);
}
@@ -47,7 +52,7 @@ public class FFmpegVideoConverter implements VideoConverter {
final var collectionMap = dumpCollections(subtitles);
final var out = getTempFile("mkv"); //Soft subtitles are only supported by mkv apparently
final var args = new ArrayList();
- args.add(ffmpegPath.toString());
+ args.add(getFFmpegPath());
args.add("-i");
args.add(videoPath.toString());
collectionMap.forEach((c, p) -> {
@@ -66,11 +71,11 @@ public class FFmpegVideoConverter implements VideoConverter {
args.add("-map");
args.add(String.valueOf(n));
args.add("-metadata:s:s:" + n);
- args.add("language=" + c.language());
+ args.add("language=" + c.locale().getISO3Language());
});
args.add(out.toString());
run(args);
- return new FileVideoImpl(out, new VideoInfoImpl("mkv"));
+ return new FileVideoImpl(out, new VideoInfoImpl("mkv", video.info().width(), video.info().height(), video.info().duration()));
}
@Override
@@ -80,7 +85,7 @@ public class FFmpegVideoConverter implements VideoConverter {
final var out = getTempFile(video.info().videoFormat());
final var subtitleArg = subtitleConverter.formatName().equalsIgnoreCase("ass") ? "ass=" + subtitlesPath : "subtitles=" + subtitlesPath;
final var args = List.of(
- ffmpegPath.toString(),
+ getFFmpegPath(),
"-i",
videoPath.toString(),
"-vf",
@@ -97,7 +102,7 @@ public class FFmpegVideoConverter implements VideoConverter {
final var audioPath = getTempFile(".wav");
final var dumpVideoPath = getTempFile("." + video.info().videoFormat());
final var args = List.of(
- ffmpegPath.toString(),
+ getFFmpegPath(),
"-i",
videoPath.toString(),
"-map",
@@ -129,7 +134,7 @@ public class FFmpegVideoConverter implements VideoConverter {
}
private SequencedMap dumpCollections(final Collection collections) throws IOException {
- final var ret = new LinkedHashMap(collections.size());
+ final var ret = LinkedHashMap.newLinkedHashMap(collections.size());
for (final var subtitles : collections) {
ret.put(subtitles, dumpSubtitles(subtitles));
}
@@ -148,23 +153,7 @@ public class FFmpegVideoConverter implements VideoConverter {
return path;
}
- private void run(final String... args) throws IOException {
- run(Arrays.asList(args));
- }
-
- private void run(final List args) throws IOException {
- final var builder = new ProcessBuilder(args);
- builder.inheritIO();
- builder.redirectErrorStream(true);
- final var process = builder.start();
- try {
- process.waitFor(1, TimeUnit.HOURS);
- } catch (final InterruptedException e) {
- Thread.currentThread().interrupt();
- process.destroy();
- }
- if (process.exitValue() != 0) {
- throw new IOException("FFmpeg exited with code " + process.exitValue());
- }
+ private String getFFmpegPath() {
+ return Files.isRegularFile(bundledPath) ? bundledPath.toString() : systemPath.toString();
}
}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFprobeVideoLoader.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFprobeVideoLoader.java
new file mode 100644
index 0000000..272d55b
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/ffmpeg/FFprobeVideoLoader.java
@@ -0,0 +1,51 @@
+package com.github.gtache.autosubtitle.ffmpeg;
+
+import com.github.gtache.autosubtitle.Video;
+import com.github.gtache.autosubtitle.VideoLoader;
+import com.github.gtache.autosubtitle.impl.FileVideoImpl;
+import com.github.gtache.autosubtitle.impl.VideoInfoImpl;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFprobeBundledPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFprobeSystemPath;
+import com.github.gtache.autosubtitle.process.impl.AbstractProcessRunner;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * FFprobe implementation of {@link VideoLoader}
+ */
+@Singleton
+public class FFprobeVideoLoader extends AbstractProcessRunner implements VideoLoader {
+
+ private final Path bundledPath;
+ private final Path systemPath;
+
+ @Inject
+ FFprobeVideoLoader(@FFprobeBundledPath final Path bundledPath, @FFprobeSystemPath final Path systemPath) {
+ this.bundledPath = requireNonNull(bundledPath);
+ this.systemPath = requireNonNull(systemPath);
+ }
+
+ @Override
+ public Video loadVideo(final Path path) throws IOException {
+ final var result = run(getFFprobePath(), "-v", "error", "-select_streams", "v", "-show_entries", "stream=width,height,duration", "-of", "csv=p=0", path.toString());
+ final var resolution = result.output().getLast();
+ final var split = resolution.split(",");
+ final var width = Integer.parseInt(split[0]);
+ final var height = Integer.parseInt(split[1]);
+ final var filename = path.getFileName().toString();
+ final var extension = filename.substring(filename.lastIndexOf('.') + 1);
+ final var duration = (long) (Double.parseDouble(split[2]) * 1000L);
+ final var info = new VideoInfoImpl(extension, width, height, duration);
+ return new FileVideoImpl(path, info);
+ }
+
+ private String getFFprobePath() {
+ return Files.isRegularFile(bundledPath) ? bundledPath.toString() : systemPath.toString();
+ }
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFBundledRoot.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFBundledRoot.java
new file mode 100644
index 0000000..b96beb8
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFBundledRoot.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+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 FFBundledRoot {
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegBundledPath.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegBundledPath.java
new file mode 100644
index 0000000..3d16cf7
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegBundledPath.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+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 FFmpegBundledPath {
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegModule.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegModule.java
new file mode 100644
index 0000000..b005dbb
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegModule.java
@@ -0,0 +1,23 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+import com.github.gtache.autosubtitle.VideoConverter;
+import com.github.gtache.autosubtitle.VideoLoader;
+import com.github.gtache.autosubtitle.ffmpeg.FFmpegVideoConverter;
+import com.github.gtache.autosubtitle.ffmpeg.FFprobeVideoLoader;
+import dagger.Binds;
+import dagger.Module;
+
+import javax.inject.Singleton;
+
+@Module
+public interface FFmpegModule {
+
+ @Binds
+ @Singleton
+ VideoConverter bindsVideoConverter(final FFmpegVideoConverter converter);
+
+ @Binds
+ @Singleton
+ VideoLoader bindsVideoLoader(final FFprobeVideoLoader loader);
+
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegSystemPath.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegSystemPath.java
new file mode 100644
index 0000000..6b58fa3
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegSystemPath.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+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 FFmpegSystemPath {
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegVersion.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegVersion.java
new file mode 100644
index 0000000..a883339
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFmpegVersion.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+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 FFmpegVersion {
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFprobeBundledPath.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFprobeBundledPath.java
new file mode 100644
index 0000000..9869e9e
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFprobeBundledPath.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+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 FFprobeBundledPath {
+}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFprobeSystemPath.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFprobeSystemPath.java
new file mode 100644
index 0000000..b1ec1a6
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/modules/ffmpeg/FFprobeSystemPath.java
@@ -0,0 +1,16 @@
+package com.github.gtache.autosubtitle.modules.ffmpeg;
+
+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 FFprobeSystemPath {
+}
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 b115e42..eec7f82 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
@@ -1,15 +1,62 @@
package com.github.gtache.autosubtitle.setup.ffmpeg;
+import com.github.gtache.autosubtitle.impl.Architecture;
+import com.github.gtache.autosubtitle.impl.OS;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegBundledPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegSystemPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegVersion;
+import com.github.gtache.autosubtitle.process.impl.AbstractProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupManager;
+import com.github.gtache.autosubtitle.setup.SetupStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
/**
* Manager managing the FFmpeg installation
*/
-public class FFmpegSetupManager implements SetupManager {
+public class FFmpegSetupManager extends AbstractProcessRunner implements SetupManager {
+ private static final Logger logger = LogManager.getLogger(FFmpegSetupManager.class);
+ private final Path bundledPath;
+ private final Path systemPath;
+ private final String version;
+ private final OS os;
+ private final Architecture architecture;
+ private final String executableExtension;
+
+ @Inject
+ FFmpegSetupManager(@FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath, @FFmpegVersion final String version, final OS os, final Architecture architecture) {
+ this.bundledPath = Objects.requireNonNull(bundledPath);
+ this.systemPath = Objects.requireNonNull(systemPath);
+ this.version = Objects.requireNonNull(version);
+ this.os = Objects.requireNonNull(os);
+ this.architecture = Objects.requireNonNull(architecture);
+ this.executableExtension = os == OS.WINDOWS ? ".exe" : "";
+ }
+
@Override
- public boolean isInstalled() throws SetupException {
- return checkSystemFFmpeg() || checkBundledFFmpeg();
+ public String name() {
+ return "FFmpeg";
+ }
+
+ @Override
+ public SetupStatus status() {
+ try {
+ if (checkSystemFFmpeg() || checkBundledFFmpeg()) {
+ return SetupStatus.INSTALLED;
+ } else {
+ return SetupStatus.NOT_INSTALLED;
+ }
+ } catch (final IOException e) {
+ logger.error("Error checking status of {}", name(), e);
+ return SetupStatus.ERRORED;
+ }
}
@Override
@@ -22,21 +69,17 @@ public class FFmpegSetupManager implements SetupManager {
}
- @Override
- public boolean isUpdateAvailable() throws SetupException {
- return false;
- }
-
@Override
public void update() throws SetupException {
}
- private boolean checkSystemFFmpeg() {
- return false;
+ private boolean checkSystemFFmpeg() throws IOException {
+ final var result = run(systemPath.toString(), "-h");
+ return result.exitCode() == 0;
}
- private boolean checkBundledFFmpeg() {
- return false;
+ private boolean checkBundledFFmpeg() throws IOException {
+ return Files.isRegularFile(bundledPath);
}
}
diff --git a/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/modules/ffmpeg/FFmpegSetupModule.java b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/modules/ffmpeg/FFmpegSetupModule.java
new file mode 100644
index 0000000..3ef7b2c
--- /dev/null
+++ b/ffmpeg/src/main/java/com/github/gtache/autosubtitle/setup/modules/ffmpeg/FFmpegSetupModule.java
@@ -0,0 +1,75 @@
+package com.github.gtache.autosubtitle.setup.modules.ffmpeg;
+
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFBundledRoot;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegBundledPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegSystemPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFmpegVersion;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFprobeBundledPath;
+import com.github.gtache.autosubtitle.modules.ffmpeg.FFprobeSystemPath;
+import com.github.gtache.autosubtitle.modules.impl.ExecutableExtension;
+import com.github.gtache.autosubtitle.setup.SetupManager;
+import com.github.gtache.autosubtitle.setup.ffmpeg.FFmpegSetupManager;
+import com.github.gtache.autosubtitle.setup.modules.impl.VideoConverterSetup;
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
+import javax.inject.Singleton;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Dagger module for FFmpeg setup
+ */
+@Module
+public abstract class FFmpegSetupModule {
+
+ private static final String FFMPEG = "ffmpeg";
+ private static final String FFPROBE = "ffprobe";
+
+ @Binds
+ @VideoConverterSetup
+ abstract SetupManager bindsFFmpegSetupManager(final FFmpegSetupManager manager);
+
+ @Provides
+ @Singleton
+ @FFBundledRoot
+ static Path providesFFBundledRoot() {
+ return Paths.get("tools", FFMPEG);
+ }
+
+ @Provides
+ @Singleton
+ @FFprobeBundledPath
+ static Path providesFFProbeBundledPath(@FFBundledRoot final Path root, @ExecutableExtension final String extension) {
+ return root.resolve(FFPROBE + extension);
+ }
+
+ @Provides
+ @Singleton
+ @FFprobeSystemPath
+ static Path providesFFProbeSystemPath(@ExecutableExtension final String extension) {
+ return Paths.get(FFPROBE + extension);
+ }
+
+ @Provides
+ @Singleton
+ @FFmpegBundledPath
+ static Path providesFFmpegBundledPath(@FFBundledRoot final Path root, @ExecutableExtension final String extension) {
+ return root.resolve(FFMPEG + extension);
+ }
+
+ @Provides
+ @Singleton
+ @FFmpegSystemPath
+ static Path providesFFmpegSystemPath(@ExecutableExtension final String extension) {
+ return Paths.get(FFMPEG + extension);
+ }
+
+ @Provides
+ @Singleton
+ @FFmpegVersion
+ static String providesFFmpegVersion() {
+ return "7.0.1";
+ }
+}
diff --git a/ffmpeg/src/main/java/module-info.java b/ffmpeg/src/main/java/module-info.java
new file mode 100644
index 0000000..0faf6e0
--- /dev/null
+++ b/ffmpeg/src/main/java/module-info.java
@@ -0,0 +1,14 @@
+/**
+ * FFmpeg module for auto-subtitle
+ */
+module com.github.gtache.autosubtitle.ffmpeg {
+ requires transitive com.github.gtache.autosubtitle.core;
+ requires transitive dagger;
+ requires transitive javax.inject;
+ requires org.apache.logging.log4j;
+
+ exports com.github.gtache.autosubtitle.ffmpeg;
+ exports com.github.gtache.autosubtitle.modules.ffmpeg;
+ exports com.github.gtache.autosubtitle.setup.ffmpeg;
+ exports com.github.gtache.autosubtitle.setup.modules.ffmpeg;
+}
\ No newline at end of file
diff --git a/fx/pom.xml b/fx/pom.xml
index 6b07449..48b3664 100644
--- a/fx/pom.xml
+++ b/fx/pom.xml
@@ -11,6 +11,10 @@
autosubtitle-fx
+
+ 22.0.1
+
+
com.github.gtache.autosubtitle
@@ -24,15 +28,19 @@
com.google.dagger
dagger
+
+ org.apache.logging.log4j
+ log4j-api
+
org.openjfx
javafx-media
- 22.0.1
+ ${javafx.version}
org.openjfx
javafx-fxml
- 22.0.1
+ ${javafx.version}
diff --git a/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainController.java b/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainController.java
index 9c1a469..cf72ea2 100644
--- a/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainController.java
+++ b/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainController.java
@@ -1,146 +1,42 @@
package com.github.gtache.autosubtitle.gui.fx;
-import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
-import com.github.gtache.autosubtitle.subtitle.Subtitle;
-import com.github.gtache.autosubtitle.subtitle.SubtitleExtractor;
-import com.github.gtache.autosubtitle.VideoConverter;
import com.github.gtache.autosubtitle.gui.MainController;
-import com.github.gtache.autosubtitle.impl.FileVideoImpl;
-import javafx.beans.binding.Bindings;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.event.ActionEvent;
import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
-import javafx.scene.control.TextField;
-import javafx.scene.layout.StackPane;
-import javafx.scene.media.Media;
-import javafx.scene.media.MediaPlayer;
-import javafx.scene.media.MediaView;
-import javafx.stage.FileChooser;
-import javafx.stage.Window;
+import javafx.scene.control.TabPane;
import javax.inject.Inject;
-import java.nio.file.Path;
-import java.time.Duration;
-import java.time.LocalTime;
-import java.util.Comparator;
-
-import static java.util.Objects.requireNonNull;
+import javax.inject.Singleton;
+import java.util.Objects;
/**
* FX implementation of {@link MainController}
*/
+@Singleton
public class FXMainController implements MainController {
@FXML
- private MediaView videoView;
- @FXML
- private TextField fileField;
- @FXML
- private Button extractButton;
- @FXML
- private Button resetButton;
- @FXML
- private Button exportButton;
- @FXML
- private TableView subtitlesTable;
- @FXML
- private TableColumn startColumn;
- @FXML
- private TableColumn endColumn;
- @FXML
- private TableColumn textColumn;
- @FXML
- private StackPane stackPane;
+ private TabPane tabPane;
private final FXMainModel model;
- private final SubtitleExtractor subtitleExtractor;
- private final VideoConverter videoConverter;
@Inject
- FXMainController(final FXMainModel model, final SubtitleExtractor subtitleExtractor, final VideoConverter videoConverter) {
- this.model = requireNonNull(model);
- this.subtitleExtractor = requireNonNull(subtitleExtractor);
- this.videoConverter = requireNonNull(videoConverter);
+ FXMainController(final FXMainModel model) {
+ this.model = Objects.requireNonNull(model);
}
@FXML
private void initialize() {
- extractButton.disableProperty().bind(model.videoProperty().isNull());
- resetButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()));
- exportButton.disableProperty().bind(Bindings.isEmpty(model.subtitles()));
-
- subtitlesTable.setItems(model.subtitles());
- startColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue() == null ? null : param.getValue().start()));
- endColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue() == null ? null : param.getValue().end()));
- textColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue() == null ? "" : param.getValue().content()));
-
- model.selectedSubtitleProperty().addListener(new ChangeListener() {
- @Override
- public void changed(final ObservableValue extends EditableSubtitle> observable, final EditableSubtitle oldValue, final EditableSubtitle newValue) {
- if (newValue != null) {
- videoView.getMediaPlayer().seek(Duration.of(newValue.start().to));
- }
- }
- });
- }
-
- @FXML
- private void fileButtonPressed() {
- final var filePicker = new FileChooser();
- final var file = filePicker.showOpenDialog(window());
- if (file != null) {
- loadVideo(file.toPath());
- }
+ tabPane.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> model.selectTab(newValue.intValue()));
+ model.selectedTabProperty().addListener((observable, oldValue, newValue) -> tabPane.getSelectionModel().select(newValue.intValue()));
}
@Override
- public void extractSubtitles() {
- if (model.video() != null) {
- final var subtitles = subtitleExtractor.extract(model.video());
- model.subtitles().setAll(subtitles.stream().sorted(Comparator.comparing(Subtitle::start)).toList());
- }
- }
-
- @Override
- public void loadVideo(final Path file) {
- fileField.setText(file.toAbsolutePath().toString());
- model.videoProperty().set(new FileVideoImpl(file));
- final var media = new Media(file.toUri().toString());
- final var player = new MediaPlayer(media);
- videoView.getMediaPlayer().dispose();
- videoView.setMediaPlayer(player);
+ public void selectTab(final int index) {
+ model.selectTab(index);
}
@Override
public FXMainModel model() {
return model;
}
-
- public Window window() {
- return videoView.getScene().getWindow();
- }
-
- @FXML
- private void extractPressed(final ActionEvent actionEvent) {
- extractSubtitles();
- }
-
- @FXML
- private void exportPressed(final ActionEvent actionEvent) {
- final var filePicker = new FileChooser();
- final var file = filePicker.showSaveDialog(window());
- if (file != null) {
- videoConverter.addSoftSubtitles(model.video(), model.subtitles());
- }
- }
-
- @FXML
- private void resetButtonPressed(final ActionEvent actionEvent) {
-
- }
}
diff --git a/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainModel.java b/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainModel.java
index 0da134b..04a38a6 100644
--- a/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainModel.java
+++ b/fx/src/main/java/com/github/gtache/autosubtitle/gui/fx/FXMainModel.java
@@ -1,51 +1,36 @@
package com.github.gtache.autosubtitle.gui.fx;
-import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
-import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.gui.MainModel;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.SimpleIntegerProperty;
import javax.inject.Inject;
+import javax.inject.Singleton;
/**
* FX implementation of {@link MainModel}
*/
+@Singleton
public class FXMainModel implements MainModel {
- private final ObjectProperty