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

@@ -8,6 +8,7 @@ import java.nio.file.Path;
/**
* Represents a file
*/
@FunctionalInterface
public interface File {
/**
* @return The file input stream

View File

@@ -54,7 +54,7 @@ public enum Language {
static {
final Map<String, Language> map = new java.util.HashMap<>();
for (final var language : Language.values()) {
for (final var language : values()) {
map.put(language.name().toLowerCase(), language);
map.put(language.englishName.toLowerCase(), language);
map.put(language.iso2, language);

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import java.io.IOException;
@@ -16,40 +17,44 @@ public interface VideoConverter {
*
* @param video The video
* @param subtitles The subtitles collections to add
* @param options The export options for the subtitles
* @return The modified video
* @throws IOException If an I/O error occurs
*/
Video addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles) throws IOException;
Video addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final ExportOptions options) throws IOException;
/**
* Adds soft subtitles to the given video
*
* @param video The video
* @param subtitles The subtitles collections to add
* @param options The export options for the subtitles
* @param path The output path
* @throws IOException If an I/O error occurs
*/
void addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final Path path) throws IOException;
void addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final ExportOptions options, final Path path) throws IOException;
/**
* Adds hard subtitles to the given video
*
* @param video The video
* @param subtitles The subtitle collection to add
* @param options The export options for the subtitles
* @return The modified video
* @throws IOException If an I/O error occurs
*/
Video addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles) throws IOException;
Video addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final ExportOptions options) throws IOException;
/**
* Adds hard subtitles to the given video
*
* @param video The video
* @param subtitles The subtitle collection to add
* @param options The export options for the subtitles
* @param path The output path
* @throws IOException If an I/O error occurs
*/
void addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final Path path) throws IOException;
void addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final ExportOptions options, final Path path) throws IOException;
/**
* Extracts the audio from the given video

View File

@@ -14,9 +14,8 @@ public interface Archiver {
*
* @param files The files to zip
* @param destination The zipped file
* @throws IOException if an error occurs
*/
void compress(final List<Path> files, final Path destination) throws IOException;
void compress(final List<Path> files, final Path destination);
/**
* Unzips an archive to the given destination

View File

@@ -26,7 +26,6 @@ public interface ProcessListener {
*
* @param duration The maximum time to wait
* @return The process result
* @throws IOException if an error occurs
*/
ProcessResult join(final Duration duration) throws IOException;
ProcessResult join(final Duration duration);
}

View File

@@ -17,9 +17,8 @@ public interface SetupManager {
/**
* @return whether the component is installed
* @throws SetupException if an error occurred
*/
boolean isInstalled() throws SetupException;
boolean isInstalled();
/**
* Installs the component
@@ -46,9 +45,8 @@ public interface SetupManager {
* Checks if an update is available for the component
*
* @return whether an update is available
* @throws SetupException if an error occurred during the check
*/
boolean isUpdateAvailable() throws SetupException;
boolean isUpdateAvailable();
/**
* Updates the component

View File

@@ -0,0 +1,19 @@
package com.github.gtache.autosubtitle.subtitle;
import com.github.gtache.autosubtitle.subtitle.converter.FormatOptions;
/**
* Represents the subtitles export options
*/
public interface ExportOptions {
/**
* @return The output format
*/
OutputFormat outputFormat();
/**
* @return The subtitles format options
*/
FormatOptions formatOptions();
}

View File

@@ -0,0 +1,14 @@
package com.github.gtache.autosubtitle.subtitle;
import com.github.gtache.autosubtitle.subtitle.converter.ParseOptions;
/**
* Represents the subtitles import options
*/
public interface ImportOptions {
/**
* @return The options for subtitle parsing
*/
ParseOptions parseOptions();
}

View File

@@ -1,7 +1,6 @@
package com.github.gtache.autosubtitle.subtitle;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.subtitle.converter.ParseException;
import java.io.IOException;
@@ -18,33 +17,34 @@ public interface SubtitleImporterExporter<T extends Subtitle> {
/**
* Imports subtitles from a file
*
* @param file The path to the file
* @return A mapping of langauge to collection
* @param file The path to the file
* @param options The import options
* @return A mapping of language to collection
* @throws IOException If an error occurred
* @throws ParseException If an error occurred while parsing a subtitle
*/
Map<Language, SubtitleCollection<T>> importSubtitles(final Path file) throws IOException, ParseException;
Map<Language, SubtitleCollection<T>> importSubtitles(final Path file, final ImportOptions options) throws IOException, ParseException;
/**
* Exports multiple collections to a file
*
* @param collections The subtitle collections
* @param videoInfo The video info (e.g. ASS format uses it)
* @param options The export options
* @param file The path to the file
* @throws IOException If an error occurred
*/
void exportSubtitles(final Collection<? extends SubtitleCollection<?>> collections, final VideoInfo videoInfo, final Path file) throws IOException;
void exportSubtitles(final Collection<? extends SubtitleCollection<?>> collections, final ExportOptions options, final Path file) throws IOException;
/**
* Exports a single collection to a file
*
* @param collection The subtitle collection
* @param videoInfo The video info (e.g. ASS format uses it)
* @param options The export options
* @param file The path to the file
* @throws IOException If an error occurred
*/
default void exportSubtitles(final SubtitleCollection<?> collection, final VideoInfo videoInfo, final Path file) throws IOException {
exportSubtitles(List.of(collection), videoInfo, file);
default void exportSubtitles(final SubtitleCollection<?> collection, final ExportOptions options, final Path file) throws IOException {
exportSubtitles(List.of(collection), options, file);
}
/**

View File

@@ -0,0 +1,19 @@
package com.github.gtache.autosubtitle.subtitle.converter;
/**
* Exception thrown when an error occurs during subtitle formatting
*/
public class FormatException extends Exception {
public FormatException(final String message) {
super(message);
}
public FormatException(final String message, final Throwable cause) {
super(message, cause);
}
public FormatException(final Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,20 @@
package com.github.gtache.autosubtitle.subtitle.converter;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.subtitle.Font;
/**
* Represents the subtitle format options
*/
public interface FormatOptions {
/**
* @return the current video info
*/
VideoInfo videoInfo();
/**
* @return The default font to use when not specified
*/
Font defaultFont();
}

View File

@@ -0,0 +1,24 @@
package com.github.gtache.autosubtitle.subtitle.converter;
import com.github.gtache.autosubtitle.subtitle.Font;
/**
* Represents the parse options
*/
public interface ParseOptions {
/**
* @return The max length in characters for a subtitle line
*/
int maxLineLength();
/**
* @return The max number of lines for a subtitle
*/
int maxLines();
/**
* @return The default font to use when not specified
*/
Font defaultFont();
}

View File

@@ -1,6 +1,5 @@
package com.github.gtache.autosubtitle.subtitle.converter;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
@@ -9,7 +8,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
/**
* Converts subtitles to a specific format (e.g. srt, ssa, ass, ...) and vice-versa
* Converts subtitles to a specific format (e.g. srt, ssa, ass, ...) and vice versa
*/
public interface SubtitleConverter<T extends Subtitle> {
@@ -17,22 +16,24 @@ public interface SubtitleConverter<T extends Subtitle> {
* Converts the subtitle collection
*
* @param collection The collection
* @param videoInfo The video info (e.g. ASS format uses it)
* @param options The format options
* @return The converted subtitles as the content of a file
* @throws FormatException If an error occurred
*/
String format(final SubtitleCollection<?> collection, final VideoInfo videoInfo);
String format(final SubtitleCollection<?> collection, final FormatOptions options) throws FormatException;
/**
* Parses a subtitle collection
*
* @param file The path to the file
* @param file The path to the file
* @param options The parse options
* @return The subtitle collection
* @throws ParseException If an error occurred
*/
default SubtitleCollection<T> parse(final Path file) throws ParseException {
default SubtitleCollection<T> parse(final Path file, final ParseOptions options) throws ParseException {
try {
final var content = Files.readString(file);
return parse(content);
return parse(content, options);
} catch (final IOException e) {
throw new ParseException(e);
}
@@ -42,10 +43,11 @@ public interface SubtitleConverter<T extends Subtitle> {
* Parses a subtitle collection
*
* @param content The content of the file
* @param options The conversion options
* @return The subtitle collection
* @throws ParseException If an error occurred
*/
SubtitleCollection<T> parse(String content) throws ParseException;
SubtitleCollection<T> parse(String content, ParseOptions options) throws ParseException;
/**
* Check if the parser can parse the given file

View File

@@ -1,5 +1,7 @@
package com.github.gtache.autosubtitle.subtitle.converter;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import java.util.Collection;
/**
@@ -19,4 +21,14 @@ public interface SubtitleConverterProvider {
* @return The converter (or null if not found)
*/
SubtitleConverter<?> getConverter(final String format);
/**
* Returns the converter for the given format
*
* @param format The format
* @return The converter (or null if not found)
*/
default SubtitleConverter<?> getConverter(final OutputFormat format) {
return getConverter(format.name());
}
}

View File

@@ -0,0 +1,25 @@
package com.github.gtache.autosubtitle.subtitle.extractor;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.subtitle.converter.ParseOptions;
/**
* Options for subtitle extraction
*/
public interface ExtractOptions {
/**
* @return The language of the subtitles
*/
Language language();
/**
* @return The extraction model
*/
ExtractionModel model();
/**
* @return The subtitles parsing options
*/
ParseOptions parseOptions();
}

View File

@@ -3,6 +3,7 @@ package com.github.gtache.autosubtitle.subtitle.extractor;
/**
* An extraction model
*/
@FunctionalInterface
public interface ExtractionModel {
/**
* @return the name of the model

View File

@@ -1,7 +1,6 @@
package com.github.gtache.autosubtitle.subtitle.extractor;
import com.github.gtache.autosubtitle.Audio;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
@@ -33,46 +32,20 @@ public interface SubtitleExtractor<T extends Subtitle> {
/**
* Extracts the subtitles from a video
*
* @param video The video
* @param model The model to use
* @param video The video
* @param options The language of the audio
* @return The extracted subtitle collection
* @throws ExtractException If an error occurs
*/
default SubtitleCollection<T> extract(final Video video, final ExtractionModel model) throws ExtractException {
return extract(video, Language.AUTO, model);
}
/**
* Extracts the subtitles from a video
*
* @param video The video
* @param language The language of the audio
* @param model The model to use
* @return The extracted subtitle collection
* @throws ExtractException If an error occurs
*/
SubtitleCollection<T> extract(final Video video, final Language language, final ExtractionModel model) throws ExtractException;
SubtitleCollection<T> extract(final Video video, final ExtractOptions options) throws ExtractException;
/**
* Extracts the subtitles from an audio
*
* @param audio The audio
* @param model The model to use
* @param audio The audio
* @param options The extraction options
* @return The extracted subtitle collection
* @throws ExtractException If an error occurs
*/
default SubtitleCollection<T> extract(final Audio audio, final ExtractionModel model) throws ExtractException {
return extract(audio, Language.AUTO, model);
}
/**
* Extracts the subtitles from an audio
*
* @param audio The audio
* @param language The language of the audio
* @param model The model to use
* @return The extracted subtitle collection
* @throws ExtractException If an error occurs
*/
SubtitleCollection<T> extract(final Audio audio, final Language language, final ExtractionModel model) throws ExtractException;
SubtitleCollection<T> extract(final Audio audio, final ExtractOptions options) throws ExtractException;
}

View File

@@ -1,36 +1,36 @@
package com.github.gtache.autosubtitle.subtitle;
import com.github.gtache.autosubtitle.VideoInfo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import static java.util.Objects.requireNonNull;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class TestSubtitleImporterExporter {
private final SubtitleImporterExporter<Subtitle> importerExporter;
private final SubtitleCollection<Subtitle> subtitleCollection;
private final ExportOptions options;
TestSubtitleImporterExporter(@Mock final SubtitleCollection<Subtitle> subtitleCollection) {
TestSubtitleImporterExporter(@Mock final SubtitleCollection<Subtitle> subtitleCollection, @Mock final ExportOptions options) {
this.subtitleCollection = requireNonNull(subtitleCollection);
this.options = requireNonNull(options);
this.importerExporter = spy(SubtitleImporterExporter.class);
}
@Test
void testExportSubtitleCollection() throws IOException {
final var videoInfo = Mockito.mock(VideoInfo.class);
final var file = mock(Path.class);
final var file = Paths.get("path");
importerExporter.exportSubtitles(subtitleCollection, videoInfo, file);
verify(importerExporter).exportSubtitles(List.of(subtitleCollection), videoInfo, file);
importerExporter.exportSubtitles(subtitleCollection, options, file);
verify(importerExporter).exportSubtitles(List.of(subtitleCollection), options, file);
}
}

View File

@@ -11,11 +11,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@@ -23,11 +22,14 @@ class TestSubtitleConverter {
private final SubtitleConverter<Subtitle> subtitleConverter;
private final SubtitleCollection<Subtitle> subtitleCollection;
private final ParseOptions options;
TestSubtitleConverter(@Mock final SubtitleConverter<Subtitle> subtitleConverter,
@Mock final SubtitleCollection<Subtitle> subtitleCollection) {
this.subtitleConverter = Objects.requireNonNull(subtitleConverter);
this.subtitleCollection = Objects.requireNonNull(subtitleCollection);
@Mock final SubtitleCollection<Subtitle> subtitleCollection,
@Mock final ParseOptions options) {
this.subtitleConverter = requireNonNull(subtitleConverter);
this.subtitleCollection = requireNonNull(subtitleCollection);
this.options = requireNonNull(options);
}
@Test
@@ -35,19 +37,19 @@ class TestSubtitleConverter {
final var file = tempDir.resolve("test.srt");
final var string = "test";
Files.writeString(file, string);
when(subtitleConverter.parse(file)).thenCallRealMethod();
when(subtitleConverter.parse(string)).thenReturn(subtitleCollection);
when(subtitleConverter.parse(file, options)).thenCallRealMethod();
when(subtitleConverter.parse(string, options)).thenReturn(subtitleCollection);
assertEquals(subtitleCollection, subtitleConverter.parse(file));
assertEquals(subtitleCollection, subtitleConverter.parse(file, options));
}
@Test
void testParseException(@TempDir final Path tempDir) throws ParseException {
final var file = tempDir.resolve("test.srt");
when(subtitleConverter.parse(file)).thenCallRealMethod();
when(subtitleConverter.parse(anyString())).thenReturn(subtitleCollection);
when(subtitleConverter.parse(file, options)).thenCallRealMethod();
when(subtitleConverter.parse(anyString(), eq(options))).thenReturn(subtitleCollection);
assertThrows(ParseException.class, () -> subtitleConverter.parse(file));
assertThrows(ParseException.class, () -> subtitleConverter.parse(file, options));
}
@Test

View File

@@ -0,0 +1,32 @@
package com.github.gtache.autosubtitle.subtitle.converter;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TestSubtitleConverterProvider {
private final SubtitleConverter<?> converter;
private final SubtitleConverterProvider provider;
TestSubtitleConverterProvider(@Mock final SubtitleConverter<?> converter) {
this.converter = Objects.requireNonNull(converter);
this.provider = spy(SubtitleConverterProvider.class);
}
@Test
void testGetConverter() {
final var format = OutputFormat.SRT;
when(provider.getConverter("SRT")).thenReturn((SubtitleConverter) converter);
assertEquals(converter, provider.getConverter(format));
verify(provider).getConverter("SRT");
}
}

View File

@@ -1,55 +0,0 @@
package com.github.gtache.autosubtitle.subtitle.extractor;
import com.github.gtache.autosubtitle.Audio;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TestSubtitleExtractor {
private final SubtitleExtractor<Subtitle> subtitleExtractor;
private final SubtitleCollection<Subtitle> subtitleCollection;
private final Audio audio;
private final Video video;
private final ExtractionModel extractionModel;
TestSubtitleExtractor(@Mock final SubtitleExtractor<Subtitle> subtitleExtractor,
@Mock final SubtitleCollection<Subtitle> subtitleCollection,
@Mock final Audio audio,
@Mock final Video video,
@Mock final ExtractionModel extractionModel) {
this.subtitleExtractor = Objects.requireNonNull(subtitleExtractor);
this.subtitleCollection = Objects.requireNonNull(subtitleCollection);
this.audio = Objects.requireNonNull(audio);
this.video = Objects.requireNonNull(video);
this.extractionModel = Objects.requireNonNull(extractionModel);
}
@Test
void testExtractVideo() throws ExtractException {
when(subtitleExtractor.extract(any(Video.class), any())).thenCallRealMethod();
when(subtitleExtractor.extract(video, Language.AUTO, extractionModel)).thenReturn(subtitleCollection);
assertEquals(subtitleCollection, subtitleExtractor.extract(video, extractionModel));
}
@Test
void testExtractAudio() throws ExtractException {
when(subtitleExtractor.extract(any(Audio.class), any())).thenCallRealMethod();
when(subtitleExtractor.extract(audio, Language.AUTO, extractionModel)).thenReturn(subtitleCollection);
assertEquals(subtitleCollection, subtitleExtractor.extract(audio, extractionModel));
}
}