refactor(command): inject CommandRunner instead of static

This commit is contained in:
2026-07-02 20:04:04 +01:00
parent 947c8261fd
commit 5bebea3f95
6 changed files with 36 additions and 34 deletions

View File

@@ -2,6 +2,7 @@ package com.ddf.vodsystem.services.media;
import com.ddf.vodsystem.dto.CommandOutput; import com.ddf.vodsystem.dto.CommandOutput;
import com.ddf.vodsystem.dto.ProgressTracker; import com.ddf.vodsystem.dto.ProgressTracker;
import org.springframework.stereotype.Component;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@@ -11,10 +12,11 @@ import java.util.function.Consumer;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Component
public class CommandRunner { public class CommandRunner {
private static final Pattern timePattern = Pattern.compile("out_time_ms=(\\d+)"); private static final Pattern timePattern = Pattern.compile("out_time_ms=(\\d+)");
public static CommandOutput run(List<String> command, Consumer<String> onOutput) throws IOException, InterruptedException { public CommandOutput run(List<String> command, Consumer<String> onOutput) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(command); ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); processBuilder.redirectErrorStream(true);
@@ -41,19 +43,15 @@ public class CommandRunner {
return commandOutput; return commandOutput;
} }
public static CommandOutput run(List<String> command) throws IOException, InterruptedException { public CommandOutput run(List<String> command) throws IOException, InterruptedException {
return run(command, null); return run(command, null);
} }
public static void setProgress(String line, ProgressTracker progress, float length) { public void setProgress(String line, ProgressTracker progress, float length) {
Matcher matcher = timePattern.matcher(line); Matcher matcher = timePattern.matcher(line);
if (matcher.find()) { if (matcher.find()) {
float timeInMs = Float.parseFloat(matcher.group(1)) / 1000000f; float timeInMs = Float.parseFloat(matcher.group(1)) / 1000000f;
progress.setProgress(timeInMs / length); progress.setProgress(timeInMs / length);
} }
} }
private CommandRunner() {
// Private constructor to prevent instantiation
}
} }

View File

@@ -13,17 +13,19 @@ import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service @Service
public class CompressionService { public class CompressionService {
private static final Logger logger = LoggerFactory.getLogger(CompressionService.class); private static final Logger logger = LoggerFactory.getLogger(CompressionService.class);
private final CommandRunner commandRunner;
private static final float AUDIO_RATIO = 0.15f; private static final float AUDIO_RATIO = 0.15f;
private static final float MAX_AUDIO_BITRATE = 128f; private static final float MAX_AUDIO_BITRATE = 128f;
private static final float BITRATE_MULTIPLIER = 0.9f; private static final float BITRATE_MULTIPLIER = 0.9f;
private final Pattern timePattern = Pattern.compile("out_time_ms=(\\d+)");
public CompressionService(CommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
@Async("ffmpegTaskExecutor") @Async("ffmpegTaskExecutor")
public CompletableFuture<CommandOutput> compress(Path inputFile, public CompletableFuture<CommandOutput> compress(Path inputFile,
@@ -38,20 +40,12 @@ public class CompressionService {
outputFile, outputFile,
clipOptions clipOptions
); );
CommandOutput result = CommandRunner.run(command, line -> CommandRunner.setProgress(line, progress, clipOptions.getDuration())); CommandOutput result = commandRunner.run(command, line -> commandRunner.setProgress(line, progress, clipOptions.getDuration()));
progress.markComplete(); progress.markComplete();
return CompletableFuture.completedFuture(result); return CompletableFuture.completedFuture(result);
} }
private void setProgress(String line, ProgressTracker progress, float length) {
Matcher matcher = timePattern.matcher(line);
if (matcher.find()) {
float timeInMs = Float.parseFloat(matcher.group(1)) / 1000000f;
progress.setProgress(timeInMs / length);
}
}
private List<String> buildFilters(Float fps, Integer width, Integer height) { private List<String> buildFilters(Float fps, Integer width, Integer height) {
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
command.add("-vf"); command.add("-vf");

View File

@@ -19,9 +19,14 @@ import java.util.concurrent.Future;
@Service @Service
public class MetadataService { public class MetadataService {
private static final Logger logger = LoggerFactory.getLogger(MetadataService.class); private static final Logger logger = LoggerFactory.getLogger(MetadataService.class);
public final CommandRunner commandRunner;
private static final String DURATION = "duration"; private static final String DURATION = "duration";
public MetadataService(CommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
@Async("ffmpegTaskExecutor") @Async("ffmpegTaskExecutor")
public Future<ClipOptions> getVideoMetadata(Path file) { public Future<ClipOptions> getVideoMetadata(Path file) {
logger.info("Getting metadata for file {}", file); logger.info("Getting metadata for file {}", file);
@@ -39,7 +44,7 @@ public class MetadataService {
StringBuilder outputBuilder = new StringBuilder(); StringBuilder outputBuilder = new StringBuilder();
try { try {
CommandOutput output = CommandRunner.run(command); CommandOutput output = commandRunner.run(command);
for (String line : output.getOutput()) { for (String line : output.getOutput()) {
outputBuilder.append(line); outputBuilder.append(line);

View File

@@ -9,12 +9,14 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service @Service
public class RemuxService { public class RemuxService {
private final Pattern timePattern = Pattern.compile("out_time_ms=(\\d+)"); private final CommandRunner commandRunner;
public RemuxService(CommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
@Async("ffmpegTaskExecutor") @Async("ffmpegTaskExecutor")
public CompletableFuture<CommandOutput> remux(File inputFile, public CompletableFuture<CommandOutput> remux(File inputFile,
@@ -33,14 +35,7 @@ public class RemuxService {
outputFile.getAbsolutePath() outputFile.getAbsolutePath()
); );
return CompletableFuture.completedFuture(CommandRunner.run(command, line -> setProgress(line, remuxProgress, length))); return CompletableFuture.completedFuture(commandRunner.run(command, line ->
} commandRunner.setProgress(line, remuxProgress, length)));
private void setProgress(String line, ProgressTracker progress, float length) {
Matcher matcher = timePattern.matcher(line);
if (matcher.find()) {
float timeInMs = Float.parseFloat(matcher.group(1)) / 1000000f;
progress.setProgress(timeInMs / length);
}
} }
} }

View File

@@ -23,6 +23,11 @@ import java.util.stream.Collectors;
@Service @Service
public class StreamActionsService { public class StreamActionsService {
private static final Logger logger = LoggerFactory.getLogger(StreamActionsService.class); private static final Logger logger = LoggerFactory.getLogger(StreamActionsService.class);
private final CommandRunner commandRunner;
public StreamActionsService(CommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
/** /**
* Concatenates a list of video segments and extracts a trimmed section * Concatenates a list of video segments and extracts a trimmed section
@@ -71,7 +76,7 @@ public class StreamActionsService {
logger.info("Saving section with ({} segments) to '{}'", logger.info("Saving section with ({} segments) to '{}'",
segments.size(), outputFile); segments.size(), outputFile);
CommandRunner.run(command, line -> CommandRunner.setProgress(line, progressTracker, duration)); commandRunner.run(command, line -> commandRunner.setProgress(line, progressTracker, duration));
progressTracker.markComplete(); progressTracker.markComplete();
return CompletableFuture.completedFuture(outputFile); return CompletableFuture.completedFuture(outputFile);

View File

@@ -12,6 +12,11 @@ import java.util.List;
@Service @Service
public class ThumbnailService { public class ThumbnailService {
private static final Logger logger = LoggerFactory.getLogger(ThumbnailService.class); private static final Logger logger = LoggerFactory.getLogger(ThumbnailService.class);
private final CommandRunner commandRunner;
public ThumbnailService(CommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
@Async("ffmpegTaskExecutor") @Async("ffmpegTaskExecutor")
public void createThumbnail(Path inputFile, Path outputFile, Float timeInVideo) throws IOException, InterruptedException { public void createThumbnail(Path inputFile, Path outputFile, Float timeInVideo) throws IOException, InterruptedException {
@@ -25,6 +30,6 @@ public class ThumbnailService {
outputFile.toAbsolutePath().toString() outputFile.toAbsolutePath().toString()
); );
CommandRunner.run(command); commandRunner.run(command);
} }
} }