SRT works ; adds support for export/import ass
This commit is contained in:
@@ -4,6 +4,7 @@ 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;
|
||||
@@ -13,6 +14,7 @@ import com.github.gtache.autosubtitle.modules.setup.ffmpeg.FFmpegSystemPath;
|
||||
import com.github.gtache.autosubtitle.process.impl.AbstractProcessRunner;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
|
||||
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
|
||||
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
@@ -23,9 +25,9 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SequencedMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -37,13 +39,16 @@ public class FFmpegVideoConverter extends AbstractProcessRunner implements Video
|
||||
private static final String TEMP_FILE_PREFIX = "autosubtitle";
|
||||
private final Path bundledPath;
|
||||
private final Path systemPath;
|
||||
private final SubtitleConverter<?> subtitleConverter;
|
||||
private final SubtitleConverterProvider converterProvider;
|
||||
private final Preferences preferences;
|
||||
|
||||
@Inject
|
||||
FFmpegVideoConverter(@FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath, final Map<String, SubtitleConverter> subtitleConverters) {
|
||||
FFmpegVideoConverter(@FFmpegBundledPath final Path bundledPath, @FFmpegSystemPath final Path systemPath,
|
||||
final SubtitleConverterProvider converterProvider, final Preferences preferences) {
|
||||
this.bundledPath = requireNonNull(bundledPath);
|
||||
this.systemPath = requireNonNull(systemPath);
|
||||
this.subtitleConverter = subtitleConverters.get("srt");
|
||||
this.converterProvider = requireNonNull(converterProvider);
|
||||
this.preferences = requireNonNull(preferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,7 +61,7 @@ public class FFmpegVideoConverter extends AbstractProcessRunner implements Video
|
||||
@Override
|
||||
public void addSoftSubtitles(final Video video, final Collection<? extends SubtitleCollection<?>> subtitles, final Path path) throws IOException {
|
||||
final var videoPath = getPath(video);
|
||||
final var collectionMap = dumpCollections(subtitles);
|
||||
final var collectionMap = dumpCollections(subtitles, video.info());
|
||||
final var args = new ArrayList<String>();
|
||||
args.add(getFFmpegPath());
|
||||
args.add("-y");
|
||||
@@ -86,7 +91,7 @@ public class FFmpegVideoConverter extends AbstractProcessRunner implements Video
|
||||
args.add("mov_text");
|
||||
} else {
|
||||
args.add("-c:s");
|
||||
args.add(subtitleConverter.formatName());
|
||||
args.add("copy");
|
||||
}
|
||||
final var j = new AtomicInteger(0);
|
||||
collectionMap.forEach((c, p) -> {
|
||||
@@ -108,9 +113,9 @@ public class FFmpegVideoConverter extends AbstractProcessRunner implements Video
|
||||
@Override
|
||||
public void addHardSubtitles(final Video video, final SubtitleCollection<?> subtitles, final Path path) throws IOException {
|
||||
final var videoPath = getPath(video);
|
||||
final var subtitlesPath = dumpSubtitles(subtitles);
|
||||
final var subtitlesPath = dumpSubtitles(subtitles, video.info());
|
||||
final var escapedPath = escapeVF(subtitlesPath.toString());
|
||||
final var subtitleArg = subtitleConverter.formatName().equalsIgnoreCase("ass") ? "ass='" + escapedPath + "'" : "subtitles='" + escapedPath + "'";
|
||||
final var subtitleArg = getSubtitleConverter().formatName().equalsIgnoreCase("ass") ? "ass='" + escapedPath + "'" : "subtitles='" + escapedPath + "'";
|
||||
final var args = List.of(
|
||||
getFFmpegPath(),
|
||||
"-i",
|
||||
@@ -122,6 +127,10 @@ public class FFmpegVideoConverter extends AbstractProcessRunner implements Video
|
||||
runListen(args, Duration.ofHours(1));
|
||||
}
|
||||
|
||||
private SubtitleConverter<?> getSubtitleConverter() {
|
||||
return converterProvider.getConverter(preferences.get("outputFormat", "ass"));
|
||||
}
|
||||
|
||||
private static String escapeVF(final String path) {
|
||||
return path.replace("\\", "\\\\").replace(":", "\\:").replace("'", "'\\''")
|
||||
.replace("%", "\\%");
|
||||
@@ -165,17 +174,17 @@ public class FFmpegVideoConverter extends AbstractProcessRunner implements Video
|
||||
return path;
|
||||
}
|
||||
|
||||
private <T extends SubtitleCollection<?>> SequencedMap<T, Path> dumpCollections(final Collection<T> collections) throws IOException {
|
||||
private <T extends SubtitleCollection<?>> SequencedMap<T, Path> dumpCollections(final Collection<T> collections, final VideoInfo videoInfo) throws IOException {
|
||||
final var ret = LinkedHashMap.<T, Path>newLinkedHashMap(collections.size());
|
||||
for (final var subtitles : collections) {
|
||||
ret.put(subtitles, dumpSubtitles(subtitles));
|
||||
ret.put(subtitles, dumpSubtitles(subtitles, videoInfo));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private Path dumpSubtitles(final SubtitleCollection<?> subtitles) throws IOException {
|
||||
final var path = getTempFile("srt");
|
||||
Files.writeString(path, subtitleConverter.format(subtitles));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.gtache.autosubtitle.setup.ffmpeg;
|
||||
|
||||
import com.github.gtache.autosubtitle.archive.Archiver;
|
||||
import com.github.gtache.autosubtitle.archive.ArchiverProvider;
|
||||
import com.github.gtache.autosubtitle.impl.Architecture;
|
||||
import com.github.gtache.autosubtitle.setup.SetupException;
|
||||
import com.github.gtache.autosubtitle.setup.SetupManager;
|
||||
@@ -16,7 +16,6 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.gtache.autosubtitle.impl.Architecture.ARMEL;
|
||||
import static com.github.gtache.autosubtitle.impl.Architecture.ARMHF;
|
||||
@@ -29,14 +28,14 @@ import static java.util.Objects.requireNonNull;
|
||||
public class FFmpegSetupManager extends AbstractSetupManager {
|
||||
private static final Logger logger = LogManager.getLogger(FFmpegSetupManager.class);
|
||||
private final FFmpegSetupConfiguration configuration;
|
||||
private final Map<String, Archiver> archivers;
|
||||
private final ArchiverProvider archiverProvider;
|
||||
|
||||
@Inject
|
||||
FFmpegSetupManager(final FFmpegSetupConfiguration configuration, final Map<String, Archiver> archivers,
|
||||
FFmpegSetupManager(final FFmpegSetupConfiguration configuration, final ArchiverProvider archiverProvider,
|
||||
final HttpClient httpClient) {
|
||||
super(httpClient);
|
||||
this.configuration = requireNonNull(configuration);
|
||||
this.archivers = Map.copyOf(archivers);
|
||||
this.archiverProvider = requireNonNull(archiverProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,7 +134,7 @@ public class FFmpegSetupManager extends AbstractSetupManager {
|
||||
try {
|
||||
final var filename = from.getFileName().toString();
|
||||
final var extension = filename.substring(filename.lastIndexOf('.') + 1);
|
||||
archivers.get(extension).decompress(from, to);
|
||||
archiverProvider.getArchiver(extension).decompress(from, to);
|
||||
} catch (final IOException e) {
|
||||
throw new SetupException(e);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ 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;
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.github.gtache.autosubtitle.VideoInfo;
|
||||
import com.github.gtache.autosubtitle.impl.OS;
|
||||
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
|
||||
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter;
|
||||
import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -14,8 +15,8 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -24,14 +25,16 @@ class TestFFmpegVideoConverter {
|
||||
|
||||
private final FFmpegVideoConverter converter;
|
||||
private final SubtitleConverter subtitleConverter;
|
||||
private final SubtitleConverterProvider subtitleConverterProvider;
|
||||
private final Video video;
|
||||
private final VideoInfo videoInfo;
|
||||
private final Path tmpFile;
|
||||
private final Path outputPath;
|
||||
private final SubtitleCollection<?> collection;
|
||||
private final Preferences preferences;
|
||||
|
||||
TestFFmpegVideoConverter(@Mock final SubtitleConverter subtitleConverter, @Mock final Video video,
|
||||
@Mock final VideoInfo videoInfo, @Mock final SubtitleCollection<?> collection) throws IOException {
|
||||
TestFFmpegVideoConverter(@Mock final SubtitleConverter subtitleConverter, @Mock final SubtitleConverterProvider subtitleConverterProvider, @Mock final Video video,
|
||||
@Mock final VideoInfo videoInfo, @Mock final SubtitleCollection<?> collection, @Mock final Preferences preferences) throws IOException {
|
||||
final var output = (OS.getOS() == OS.WINDOWS ? System.getProperty("java.io.tmpdir") : "/tmp");
|
||||
final var resource = OS.getOS() == OS.WINDOWS ? "fake-ffmpeg.exe" : "fake-ffmpeg.sh";
|
||||
this.video = Objects.requireNonNull(video);
|
||||
@@ -43,7 +46,9 @@ class TestFFmpegVideoConverter {
|
||||
}
|
||||
this.outputPath = Path.of(output, "test-ffmpeg-output.txt");
|
||||
this.subtitleConverter = Objects.requireNonNull(subtitleConverter);
|
||||
this.converter = new FFmpegVideoConverter(tmpFile, tmpFile, Map.of("srt", subtitleConverter));
|
||||
this.subtitleConverterProvider = Objects.requireNonNull(subtitleConverterProvider);
|
||||
this.preferences = Objects.requireNonNull(preferences);
|
||||
this.converter = new FFmpegVideoConverter(tmpFile, tmpFile, subtitleConverterProvider, preferences);
|
||||
this.collection = Objects.requireNonNull(collection);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user