Extraction works
This commit is contained in:
@@ -4,7 +4,17 @@ 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;
|
||||
//32 bit
|
||||
I386, I486, I586, I686, X86_32,
|
||||
//PowerPC
|
||||
PPC, POWERPC,
|
||||
//64 bit
|
||||
X86, X86_64, AMD64,
|
||||
//ARM 32 bit
|
||||
ARM32, ARM, ARMV1, ARMV2, ARMV3, ARMV4, ARMV5, ARMV6, ARMV7, AARCH32,
|
||||
//ARM 64 bit
|
||||
ARM64, ARMV8, ARMV9, AARCH64,
|
||||
UNKNOWN;
|
||||
|
||||
public static Architecture getArchitecture(final String name) {
|
||||
try {
|
||||
@@ -13,4 +23,12 @@ public enum Architecture {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAMD64() {
|
||||
return this == X86 || this == X86_64 || this == AMD64;
|
||||
}
|
||||
|
||||
public boolean isARM64() {
|
||||
return this == ARM64 || this == ARMV8 || this == ARMV9 || this == AARCH64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,12 @@ import java.util.Objects;
|
||||
/**
|
||||
* Implementation of {@link AudioInfo}
|
||||
*/
|
||||
public record AudioInfoImpl(String audioFormat) implements AudioInfo {
|
||||
public record AudioInfoImpl(String audioFormat, long duration) implements AudioInfo {
|
||||
|
||||
public AudioInfoImpl {
|
||||
Objects.requireNonNull(audioFormat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String videoFormat() {
|
||||
return audioFormat;
|
||||
if (duration < 0) {
|
||||
throw new IllegalArgumentException("Duration must be positive");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.gtache.autosubtitle.setup.modules.impl;
|
||||
package com.github.gtache.autosubtitle.modules.setup.impl;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import java.lang.annotation.Documented;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.gtache.autosubtitle.setup.modules.impl;
|
||||
package com.github.gtache.autosubtitle.modules.setup.impl;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import java.lang.annotation.Documented;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.gtache.autosubtitle.setup.modules.impl;
|
||||
package com.github.gtache.autosubtitle.modules.setup.impl;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import java.lang.annotation.Documented;
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.github.gtache.autosubtitle.subtitle.modules.impl;
|
||||
package com.github.gtache.autosubtitle.modules.subtitles.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
|
||||
*/
|
||||
@@ -14,6 +12,5 @@ import javax.inject.Singleton;
|
||||
public interface ConverterModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
SubtitleConverter bindsSubtitleConverter(final SRTSubtitleConverter converter);
|
||||
}
|
||||
@@ -1,19 +1,15 @@
|
||||
package com.github.gtache.autosubtitle.process.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.process.ProcessListener;
|
||||
import com.github.gtache.autosubtitle.process.ProcessResult;
|
||||
import com.github.gtache.autosubtitle.process.ProcessRunner;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link ProcessRunner}
|
||||
@@ -24,29 +20,30 @@ public abstract class AbstractProcessRunner implements ProcessRunner {
|
||||
|
||||
@Override
|
||||
public ProcessResult run(final List<String> args) throws IOException {
|
||||
final var builder = new ProcessBuilder(args);
|
||||
builder.redirectErrorStream(true);
|
||||
final var process = builder.start();
|
||||
final var readFuture = CompletableFuture.supplyAsync(() -> {
|
||||
final var output = new ArrayList<String>();
|
||||
try (final var in = new BufferedReader(new InputStreamReader(new BufferedInputStream(process.getInputStream()), StandardCharsets.UTF_8))) {
|
||||
var line = in.readLine();
|
||||
final var listener = startListen(args);
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
var line = listener.readLine();
|
||||
while (line != null) {
|
||||
output.add(line);
|
||||
line = in.readLine();
|
||||
line = listener.readLine();
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.error("Error listening to process output of {}", args, e);
|
||||
}
|
||||
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);
|
||||
return listener.join(Duration.ofHours(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process start(final List<String> args) throws IOException {
|
||||
final var builder = new ProcessBuilder(args);
|
||||
builder.redirectErrorStream(true);
|
||||
return builder.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessListener startListen(final List<String> args) throws IOException {
|
||||
final var process = start(args);
|
||||
return new ProcessListenerImpl(process);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.github.gtache.autosubtitle.process.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.process.ProcessListener;
|
||||
import com.github.gtache.autosubtitle.process.ProcessResult;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ProcessListener}
|
||||
*/
|
||||
public class ProcessListenerImpl implements ProcessListener {
|
||||
|
||||
private final Process process;
|
||||
private final BufferedReader reader;
|
||||
private final List<String> output;
|
||||
|
||||
/**
|
||||
* Instantiates the listener
|
||||
*
|
||||
* @param process The process to listen to
|
||||
*/
|
||||
public ProcessListenerImpl(final Process process) {
|
||||
this.process = Objects.requireNonNull(process);
|
||||
this.reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(process.getInputStream()), StandardCharsets.UTF_8));
|
||||
this.output = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process process() {
|
||||
return process;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readLine() throws IOException {
|
||||
final var line = reader.readLine();
|
||||
if (line != null) {
|
||||
output.add(line);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessResult join(final Duration duration) throws IOException {
|
||||
try {
|
||||
process.waitFor(duration.getSeconds(), TimeUnit.SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
process.destroy();
|
||||
}
|
||||
if (process.isAlive()) {
|
||||
process.destroyForcibly();
|
||||
}
|
||||
reader.close();
|
||||
return new ProcessResultImpl(process.exitValue(), output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.github.gtache.autosubtitle.setup.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.process.impl.AbstractProcessRunner;
|
||||
import com.github.gtache.autosubtitle.setup.SetupAction;
|
||||
import com.github.gtache.autosubtitle.setup.SetupEvent;
|
||||
import com.github.gtache.autosubtitle.setup.SetupException;
|
||||
import com.github.gtache.autosubtitle.setup.SetupListener;
|
||||
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 java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Base class for all {@link SetupManager} implementations
|
||||
*/
|
||||
public abstract class AbstractSetupManager extends AbstractProcessRunner implements SetupManager {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(AbstractSetupManager.class);
|
||||
private final Set<SetupListener> listeners;
|
||||
|
||||
/**
|
||||
* Instantiates the manager
|
||||
*/
|
||||
protected AbstractSetupManager() {
|
||||
this.listeners = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final SetupListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(final SetupListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListeners() {
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reinstall() throws SetupException {
|
||||
sendStartEvent(SetupAction.UNINSTALL, name(), 0);
|
||||
uninstall();
|
||||
sendEndEvent(SetupAction.UNINSTALL, name(), -1);
|
||||
sendStartEvent(SetupAction.INSTALL, name(), -1);
|
||||
install();
|
||||
sendEndEvent(SetupAction.INSTALL, name(), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstalled() {
|
||||
return status() == SetupStatus.SYSTEM_INSTALLED || status() == SetupStatus.BUNDLE_INSTALLED || status() == SetupStatus.UPDATE_AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdateAvailable() {
|
||||
return status() == SetupStatus.UPDATE_AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetupStatus status() {
|
||||
sendStartEvent(SetupAction.CHECK, name(), 0);
|
||||
try {
|
||||
final var status = getStatus();
|
||||
sendEndEvent(SetupAction.CHECK, name(), 1);
|
||||
return status;
|
||||
} catch (final SetupException e) {
|
||||
logger.error("Error getting status of {}", name(), e);
|
||||
sendEndEvent(SetupAction.CHECK, name(), 1);
|
||||
return SetupStatus.ERRORED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Retrieves the setup status
|
||||
* @throws SetupException if an error occurred
|
||||
*/
|
||||
protected abstract SetupStatus getStatus() throws SetupException;
|
||||
|
||||
/**
|
||||
* Sends a start event
|
||||
*
|
||||
* @param action the action
|
||||
* @param target the target
|
||||
* @param progress the progress
|
||||
*/
|
||||
protected void sendStartEvent(final SetupAction action, final String target, final double progress) {
|
||||
sendStartEvent(new SetupEventImpl(action, target, progress, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an end event
|
||||
*
|
||||
* @param action the action
|
||||
* @param target the target
|
||||
* @param progress the progress
|
||||
*/
|
||||
protected void sendEndEvent(final SetupAction action, final String target, final double progress) {
|
||||
sendEndEvent(new SetupEventImpl(action, target, progress, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a start event
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
protected void sendStartEvent(final SetupEvent event) {
|
||||
listeners.forEach(listener -> listener.onActionStart(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an end event
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
protected void sendEndEvent(final SetupEvent event) {
|
||||
listeners.forEach(listener -> listener.onActionEnd(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a folder
|
||||
*
|
||||
* @param path the path
|
||||
* @throws SetupException if an error occurred
|
||||
*/
|
||||
protected void deleteFolder(final Path path) throws SetupException {
|
||||
logger.info("Deleting {}", path);
|
||||
final var index = new AtomicInteger(0);
|
||||
try (final var files = Files.walk(path)) {
|
||||
final var total = getFilesCount(path);
|
||||
files.sorted(Comparator.reverseOrder())
|
||||
.forEach(f -> {
|
||||
try {
|
||||
final var progress = index.get() / (double) total;
|
||||
sendStartEvent(SetupAction.DELETE, f.toString(), progress);
|
||||
Files.deleteIfExists(f);
|
||||
final var newProgress = index.incrementAndGet() / (double) total;
|
||||
sendEndEvent(SetupAction.DELETE, f.toString(), newProgress);
|
||||
} catch (final IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
} catch (final IOException | UncheckedIOException e) {
|
||||
throw new SetupException(e);
|
||||
}
|
||||
logger.info("{} deleted", path);
|
||||
}
|
||||
|
||||
private static long getFilesCount(final Path path) throws IOException {
|
||||
try (final var stream = Files.walk(path)) {
|
||||
return stream.count();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.github.gtache.autosubtitle.setup.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.setup.SetupAction;
|
||||
import com.github.gtache.autosubtitle.setup.SetupEvent;
|
||||
import com.github.gtache.autosubtitle.setup.SetupManager;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Implementation of {@link SetupEvent}
|
||||
*/
|
||||
public record SetupEventImpl(SetupAction action, String target, double progress,
|
||||
SetupManager setupManager) implements SetupEvent {
|
||||
|
||||
public SetupEventImpl {
|
||||
Objects.requireNonNull(action);
|
||||
Objects.requireNonNull(target);
|
||||
Objects.requireNonNull(setupManager);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.github.gtache.autosubtitle.subtitle.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.subtitle.ExtractEvent;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleExtractor;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleExtractorListener;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link SubtitleExtractor}
|
||||
*/
|
||||
public abstract class AbstractSubtitleExtractor implements SubtitleExtractor {
|
||||
|
||||
private final Set<SubtitleExtractorListener> listeners;
|
||||
|
||||
/**
|
||||
* Instantiates the extractor
|
||||
*/
|
||||
protected AbstractSubtitleExtractor() {
|
||||
this.listeners = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final SubtitleExtractorListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(final SubtitleExtractorListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListeners() {
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
protected void notifyListeners(final ExtractEvent event) {
|
||||
listeners.forEach(listener -> listener.listen(event));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.github.gtache.autosubtitle.subtitle.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.subtitle.ExtractEvent;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExtractEvent}
|
||||
*/
|
||||
public record ExtractEventImpl(String message, double progress) implements ExtractEvent {
|
||||
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package com.github.gtache.autosubtitle.subtitle.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.subtitle.Subtitle;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Converts subtitles to SRT format
|
||||
@@ -17,7 +21,13 @@ public class SRTSubtitleConverter implements SubtitleConverter {
|
||||
}
|
||||
|
||||
public String convert(final SubtitleCollection collection) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
final var subtitles = collection.subtitles().stream().sorted(Comparator.comparing(Subtitle::start).thenComparing(Subtitle::end)).toList();
|
||||
return IntStream.range(0, subtitles.size()).mapToObj(i -> {
|
||||
final var subtitle = subtitles.get(i);
|
||||
return (i + 1) + "\n" +
|
||||
subtitle.start() + " --> " + subtitle.end() + "\n" +
|
||||
subtitle.content();
|
||||
}).collect(Collectors.joining("\n\n"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
package com.github.gtache.autosubtitle.subtitle.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.Language;
|
||||
import com.github.gtache.autosubtitle.subtitle.Subtitle;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* Implementation of {@link SubtitleCollection}
|
||||
*/
|
||||
public record SubtitleCollectionImpl(Collection<? extends Subtitle> subtitles,
|
||||
Locale locale) implements SubtitleCollection {
|
||||
public record SubtitleCollectionImpl(String text, Collection<? extends Subtitle> subtitles,
|
||||
Language language) implements SubtitleCollection {
|
||||
|
||||
public SubtitleCollectionImpl {
|
||||
Objects.requireNonNull(text);
|
||||
subtitles = List.copyOf(subtitles);
|
||||
requireNonNull(locale);
|
||||
requireNonNull(language);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.github.gtache.autosubtitle.subtitle.impl;
|
||||
|
||||
import com.github.gtache.autosubtitle.subtitle.Bounds;
|
||||
import com.github.gtache.autosubtitle.subtitle.Font;
|
||||
import com.github.gtache.autosubtitle.subtitle.Subtitle;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Subtitle}
|
||||
*/
|
||||
public record SubtitleImpl(String content, long start, long end, Font font, Bounds bounds) implements Subtitle {
|
||||
public SubtitleImpl {
|
||||
Objects.requireNonNull(content);
|
||||
if (start < 0) {
|
||||
throw new IllegalArgumentException("start must be >= 0 : " + start);
|
||||
}
|
||||
if (end < 0) {
|
||||
throw new IllegalArgumentException("end must be >= 0 : " + end);
|
||||
}
|
||||
if (start > end) {
|
||||
throw new IllegalArgumentException("start must be <= end : " + start + " > " + end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,11 @@ module com.github.gtache.autosubtitle.core {
|
||||
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.setup.impl;
|
||||
exports com.github.gtache.autosubtitle.subtitle.impl;
|
||||
exports com.github.gtache.autosubtitle.setup.modules.impl;
|
||||
exports com.github.gtache.autosubtitle.subtitle.modules.impl;
|
||||
|
||||
exports com.github.gtache.autosubtitle.modules.impl;
|
||||
exports com.github.gtache.autosubtitle.modules.setup.impl;
|
||||
exports com.github.gtache.autosubtitle.modules.subtitles.impl;
|
||||
}
|
||||
Reference in New Issue
Block a user