Rework to avoid using preferences object to retrieve options

This commit is contained in:
Guillaume Tâche
2024-09-22 21:59:10 +02:00
parent 7f99c48e2c
commit c59619da2d
115 changed files with 2294 additions and 765 deletions

View File

@@ -22,7 +22,7 @@ public class TarArchiver implements Archiver {
}
@Override
public void compress(final List<Path> files, final Path destination) throws IOException {
public void compress(final List<Path> files, final Path destination) {
throw new UnsupportedOperationException("Not implemented yet");
}

View File

@@ -20,7 +20,7 @@ public class XZArchiver implements Archiver {
}
@Override
public void compress(final List<Path> files, final Path destination) throws IOException {
public void compress(final List<Path> files, final Path destination) {
throw new UnsupportedOperationException("Not implemented");
}

View File

@@ -4,14 +4,15 @@ import com.github.gtache.autosubtitle.Audio;
import com.github.gtache.autosubtitle.File;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoConverter;
import com.github.gtache.autosubtitle.VideoInfo;
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.modules.setup.ffmpeg.FFmpegBundledPath;
import com.github.gtache.autosubtitle.modules.setup.ffmpeg.FFmpegSystemPath;
import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.converter.FormatException;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
import org.apache.logging.log4j.LogManager;
@@ -28,7 +29,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.SequencedMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.prefs.Preferences;
import static java.util.Objects.requireNonNull;
@@ -41,31 +41,28 @@ public class FFmpegVideoConverter implements VideoConverter {
private final Path bundledPath;
private final Path systemPath;
private final SubtitleConverterProvider converterProvider;
private final Preferences preferences;
private final ProcessRunner processRunner;
@Inject
FFmpegVideoConverter(@FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath,
final SubtitleConverterProvider converterProvider, final Preferences preferences,
final ProcessRunner processRunner) {
final SubtitleConverterProvider converterProvider, final ProcessRunner processRunner) {
this.bundledPath = requireNonNull(bundledPath);
this.systemPath = requireNonNull(systemPath);
this.converterProvider = requireNonNull(converterProvider);
this.preferences = requireNonNull(preferences);
this.processRunner = requireNonNull(processRunner);
}
@Override
public Video addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles) throws IOException {
public Video addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final ExportOptions options) throws IOException {
final var out = getTempFile(video.info().format());
addSoftSubtitles(video, subtitles, out);
addSoftSubtitles(video, subtitles, options, out);
return new FileVideoImpl(out, video.info());
}
@Override
public void addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final Path path) throws IOException {
public void addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final ExportOptions options, final Path path) throws IOException {
final var videoPath = getPath(video);
final var collectionMap = dumpCollections(subtitles, video.info());
final var collectionMap = dumpCollections(subtitles, options);
final var args = new ArrayList<String>();
args.add(getFFmpegPath());
args.add("-y");
@@ -108,18 +105,18 @@ public class FFmpegVideoConverter implements VideoConverter {
}
@Override
public Video addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles) throws IOException {
public Video addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final ExportOptions options) throws IOException {
final var out = getTempFile(video.info().format());
addHardSubtitles(video, subtitles, out);
addHardSubtitles(video, subtitles, options, out);
return new FileVideoImpl(out, video.info());
}
@Override
public void addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final Path path) throws IOException {
public void addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final ExportOptions options, final Path path) throws IOException {
final var videoPath = getPath(video);
final var subtitlesPath = dumpSubtitles(subtitles, video.info());
final var subtitlesPath = dumpSubtitles(subtitles, options);
final var escapedPath = escapeVF(subtitlesPath.toString());
final var subtitleArg = getSubtitleConverter().formatName().equalsIgnoreCase("ass") ? "ass='" + escapedPath + "'" : "subtitles='" + escapedPath + "'";
final var subtitleArg = getSubtitleConverter(options).formatName().equalsIgnoreCase("ass") ? "ass='" + escapedPath + "'" : "subtitles='" + escapedPath + "'";
final var args = List.of(
getFFmpegPath(),
"-y",
@@ -132,8 +129,8 @@ public class FFmpegVideoConverter implements VideoConverter {
runLog(args, Duration.ofHours(1));
}
private SubtitleConverter<?> getSubtitleConverter() {
return converterProvider.getConverter(preferences.get("outputFormat", "srt"));
private SubtitleConverter<?> getSubtitleConverter(final ExportOptions options) {
return converterProvider.getConverter(options.outputFormat());
}
private static String escapeVF(final String path) {
@@ -179,18 +176,22 @@ public class FFmpegVideoConverter implements VideoConverter {
return path;
}
private <T extends SubtitleCollection<?>> SequencedMap<T, Path> dumpCollections(final Collection<T> collections, final VideoInfo videoInfo) throws IOException {
private <T extends SubtitleCollection<?>> SequencedMap<T, Path> dumpCollections(final Collection<? extends T> collections, final ExportOptions options) throws IOException {
final var ret = LinkedHashMap.<T, Path>newLinkedHashMap(collections.size());
for (final var subtitles : collections) {
ret.put(subtitles, dumpSubtitles(subtitles, videoInfo));
ret.put(subtitles, dumpSubtitles(subtitles, options));
}
return ret;
}
private Path dumpSubtitles(final SubtitleCollection<?> subtitles, final VideoInfo videoInfo) throws IOException {
final var path = getTempFile(getSubtitleConverter().formatName().toLowerCase());
Files.writeString(path, getSubtitleConverter().format(subtitles, videoInfo));
return path;
private Path dumpSubtitles(final SubtitleCollection<?> subtitles, final ExportOptions options) throws IOException {
final var path = getTempFile(getSubtitleConverter(options).formatName().toLowerCase());
try {
Files.writeString(path, getSubtitleConverter(options).format(subtitles, options.formatOptions()));
return path;
} catch (final FormatException e) {
throw new IOException(e);
}
}
private static Path getTempFile(final String extension) throws IOException {

View File

@@ -9,7 +9,6 @@ module com.github.gtache.autosubtitle.ffmpeg {
requires org.apache.logging.log4j;
requires org.tukaani.xz;
requires org.apache.commons.compress;
requires java.prefs;
exports com.github.gtache.autosubtitle.ffmpeg;
exports com.github.gtache.autosubtitle.setup.ffmpeg;

View File

@@ -8,7 +8,11 @@ import com.github.gtache.autosubtitle.impl.FileVideoImpl;
import com.github.gtache.autosubtitle.process.ProcessListener;
import com.github.gtache.autosubtitle.process.ProcessResult;
import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.converter.FormatException;
import com.github.gtache.autosubtitle.subtitle.converter.FormatOptions;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
import org.junit.jupiter.api.BeforeEach;
@@ -28,7 +32,6 @@ import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.prefs.Preferences;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.*;
@@ -40,29 +43,31 @@ class TestFFmpegVideoConverter {
private final ProcessRunner runner;
private final ProcessListener listener;
private final ProcessResult result;
private final ProcessResult processResult;
private final SubtitleConverter<?> subtitleConverter;
private final SubtitleConverterProvider subtitleConverterProvider;
private final Video video;
private final InputStream in;
private final VideoInfo videoInfo;
private final InputStream in;
private final ExportOptions options;
private final FormatOptions formatOptions;
private final SubtitleCollection<?> frCollection;
private final SubtitleCollection<?> deCollection;
private final Preferences preferences;
private final Path systemPath;
TestFFmpegVideoConverter(@Mock final SubtitleConverter<?> subtitleConverter, @Mock final ProcessRunner runner,
@Mock final SubtitleConverterProvider subtitleConverterProvider, @Mock final Video video,
@Mock final VideoInfo videoInfo, @Mock final SubtitleCollection<?> frCollection, @Mock final SubtitleCollection<?> deCollection,
@Mock final Preferences preferences, @Mock final ProcessListener listener, @Mock final InputStream in,
@Mock final ProcessResult result) {
@Mock final SubtitleConverterProvider subtitleConverterProvider, @Mock final Video video, @Mock final VideoInfo videoInfo,
@Mock final ExportOptions options, @Mock final SubtitleCollection<?> frCollection,
@Mock final SubtitleCollection<?> deCollection, @Mock final ProcessListener listener, @Mock final InputStream in,
@Mock final ProcessResult processResult, @Mock final FormatOptions formatOptions) {
this.video = requireNonNull(video);
this.runner = requireNonNull(runner);
this.result = requireNonNull(result);
this.videoInfo = requireNonNull(videoInfo);
this.runner = requireNonNull(runner);
this.options = requireNonNull(options);
this.formatOptions = requireNonNull(formatOptions);
this.processResult = requireNonNull(processResult);
this.subtitleConverter = requireNonNull(subtitleConverter);
this.subtitleConverterProvider = requireNonNull(subtitleConverterProvider);
this.preferences = requireNonNull(preferences);
this.listener = requireNonNull(listener);
this.in = requireNonNull(in);
this.systemPath = Paths.get("system");
@@ -71,25 +76,26 @@ class TestFFmpegVideoConverter {
}
@BeforeEach
void beforeEach() throws IOException {
void beforeEach() throws IOException, FormatException {
when(video.info()).thenReturn(videoInfo);
when(subtitleConverterProvider.getConverter("srt")).thenReturn((SubtitleConverter) subtitleConverter);
when(subtitleConverterProvider.getConverter(OutputFormat.SRT)).thenReturn((SubtitleConverter) subtitleConverter);
when(subtitleConverter.formatName()).thenReturn("srt");
when(subtitleConverter.format(any(), any())).thenReturn("");
when(preferences.get("outputFormat", "srt")).thenReturn("srt");
when(options.outputFormat()).thenReturn(OutputFormat.SRT);
when(options.formatOptions()).thenReturn(formatOptions);
when(video.getInputStream()).thenReturn(in);
when(frCollection.language()).thenReturn(Language.FR);
when(deCollection.language()).thenReturn(Language.DE);
when(runner.startListen(anyList())).thenReturn(listener);
when(listener.join(Duration.ofHours(1))).thenReturn(result);
when(result.exitCode()).thenReturn(0);
when(listener.join(Duration.ofHours(1))).thenReturn(processResult);
when(processResult.exitCode()).thenReturn(0);
}
@Test
void testAddSoftSubtitlesMp4() throws IOException {
void testAddSoftSubtitlesMp4() throws IOException, FormatException {
when(videoInfo.format()).thenReturn("mp4");
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, preferences, runner);
final var result = converter.addSoftSubtitles(video, List.of(frCollection, deCollection));
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, runner);
final var result = converter.addSoftSubtitles(video, List.of(frCollection, deCollection), options);
assertEquals(videoInfo, result.info());
@@ -125,8 +131,8 @@ class TestFFmpegVideoConverter {
assertTrue(args.get(5).endsWith(".srt"));
assertTrue(args.get(7).endsWith(".srt"));
assertTrue(args.get(26).endsWith(".mp4"));
verify(subtitleConverter).format(frCollection, videoInfo);
verify(subtitleConverter).format(deCollection, videoInfo);
verify(subtitleConverter).format(frCollection, formatOptions);
verify(subtitleConverter).format(deCollection, formatOptions);
verify(in).transferTo(any());
}
@@ -135,19 +141,18 @@ class TestFFmpegVideoConverter {
}
@Test
void testAddSoftSubtitlesMkvPathFile() throws IOException {
void testAddSoftSubtitlesMkvPathFile() throws IOException, FormatException {
when(videoInfo.format()).thenReturn("mkv");
doReturn(null).when(subtitleConverterProvider).getConverter("srt");
when(subtitleConverterProvider.getConverter("ass")).thenReturn((SubtitleConverter) subtitleConverter);
doReturn(null).when(subtitleConverterProvider).getConverter(OutputFormat.SRT);
when(subtitleConverterProvider.getConverter(OutputFormat.ASS)).thenReturn((SubtitleConverter) subtitleConverter);
when(subtitleConverter.formatName()).thenReturn("ass");
when(preferences.get("outputFormat", "srt")).thenReturn("ass");
when(options.outputFormat()).thenReturn(OutputFormat.ASS);
final var fileVideo = mock(FileVideoImpl.class);
when(fileVideo.info()).thenReturn(videoInfo);
final var path = Paths.get("path.mkv");
when(fileVideo.path()).thenReturn(path);
final var out = Paths.get("out.mkv");
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, preferences, runner);
converter.addSoftSubtitles(fileVideo, List.of(frCollection, deCollection), out);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, runner);
converter.addSoftSubtitles(fileVideo, List.of(frCollection, deCollection), options, out);
final var args = getArgs();
assertEquals(27, args.size());
@@ -181,16 +186,16 @@ class TestFFmpegVideoConverter {
checkEquals(argMap, args);
assertTrue(args.get(5).endsWith(".ass"));
assertTrue(args.get(7).endsWith(".ass"));
verify(subtitleConverter).format(frCollection, videoInfo);
verify(subtitleConverter).format(deCollection, videoInfo);
verify(subtitleConverter).format(frCollection, formatOptions);
verify(subtitleConverter).format(deCollection, formatOptions);
verifyNoInteractions(in);
}
@Test
void testAddHardSubtitles() throws IOException {
void testAddHardSubtitles() throws IOException, FormatException {
when(videoInfo.format()).thenReturn("mp4");
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, preferences, runner);
final var result = converter.addHardSubtitles(video, frCollection);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, runner);
final var result = converter.addHardSubtitles(video, frCollection, options);
assertEquals(videoInfo, result.info());
@@ -206,19 +211,19 @@ class TestFFmpegVideoConverter {
assertTrue(args.get(3).endsWith(".mp4"));
assertTrue(args.get(5).startsWith("subtitles="));
assertTrue(args.get(6).endsWith(".mp4"));
verify(subtitleConverter).format(frCollection, videoInfo);
verify(subtitleConverter).format(frCollection, formatOptions);
verify(in).transferTo(any());
}
@Test
void testAddHardAssSubtitles() throws IOException {
doReturn(null).when(subtitleConverterProvider).getConverter("srt");
when(subtitleConverterProvider.getConverter("ass")).thenReturn((SubtitleConverter) subtitleConverter);
void testAddHardAssSubtitles() throws IOException, FormatException {
doReturn(null).when(subtitleConverterProvider).getConverter(OutputFormat.SRT);
when(subtitleConverterProvider.getConverter(OutputFormat.ASS)).thenReturn((SubtitleConverter) subtitleConverter);
when(subtitleConverter.formatName()).thenReturn("ass");
when(preferences.get("outputFormat", "srt")).thenReturn("ass");
when(options.outputFormat()).thenReturn(OutputFormat.ASS);
when(videoInfo.format()).thenReturn("mp4");
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, preferences, runner);
final var result = converter.addHardSubtitles(video, frCollection);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, runner);
final var result = converter.addHardSubtitles(video, frCollection, options);
assertEquals(videoInfo, result.info());
@@ -234,7 +239,7 @@ class TestFFmpegVideoConverter {
assertTrue(args.get(3).endsWith(".mp4"));
assertTrue(args.get(5).startsWith("ass="));
assertTrue(args.get(6).endsWith(".mp4"));
verify(subtitleConverter).format(frCollection, videoInfo);
verify(subtitleConverter).format(frCollection, formatOptions);
verify(in).transferTo(any());
}
@@ -242,7 +247,7 @@ class TestFFmpegVideoConverter {
void testGetAudio() throws IOException {
when(videoInfo.format()).thenReturn("mp4");
when(videoInfo.duration()).thenReturn(25000L);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, preferences, runner);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, runner);
final var result = converter.getAudio(video);
assertEquals(new AudioInfoImpl("wav", 25000L), result.info());
@@ -267,10 +272,10 @@ class TestFFmpegVideoConverter {
@Test
void testGetAudioException() {
when(result.exitCode()).thenReturn(1);
when(processResult.exitCode()).thenReturn(1);
when(videoInfo.format()).thenReturn("mp4");
when(videoInfo.duration()).thenReturn(25000L);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, preferences, runner);
final var converter = new FFmpegVideoConverter(Paths.get("bundled"), systemPath, subtitleConverterProvider, runner);
assertThrows(IOException.class, () -> converter.getAudio(video));
}
@@ -280,7 +285,7 @@ class TestFFmpegVideoConverter {
Files.createFile(bundled);
when(videoInfo.format()).thenReturn("mp4");
when(videoInfo.duration()).thenReturn(25000L);
final var converter = new FFmpegVideoConverter(bundled, systemPath, subtitleConverterProvider, preferences, runner);
final var converter = new FFmpegVideoConverter(bundled, systemPath, subtitleConverterProvider, runner);
final var result = converter.getAudio(video);
assertEquals(new AudioInfoImpl("wav", 25000L), result.info());

View File

@@ -95,7 +95,7 @@ class TestFFmpegSetupManager {
}
@Test
void testGetStatusSystemException() throws IOException, SetupException {
void testGetStatusSystemException() throws IOException {
final var ffmpegPath = Paths.get("path");
when(configuration.bundledFFmpegPath()).thenReturn(ffmpegPath);
when(processRunner.run(List.of(systemPath.toString(), "-version"), Duration.ofSeconds(5))).thenThrow(IOException.class);