refactor(media): consolidate upload/edit/download into MediaService

Merge UploadService, EditService, JobOrchestrationService, and
DownloadService into a single MediaService with a unified Job lifecycle
(READY → PROCESSING → SUCCEEDED/FAILED via JobState enum).

- Add MediaController (/api/v1/media) exposing compress, save, and clip
- Add JobController (/api/v1/job) for status polling and file download
- Move clip/thumbnail download into ClipController (/{id}/media, /{id}/thumbnail)
- Move stream saveSection/clip from StreamService into MediaService
- Simplify Job DTO: remove dual ClipOptions/files, add ProgressTracker and download file
- Refactor JobRegistryService.add() → generateJob() to co-locate creation and registration
- Wire FFmpeg out_time_ms progress parsing into StreamActionsService via CommandRunner
- Rename GET /api/v1/auth/user → GET /api/v1/user/me
- Delete DownloadController, MetadataController, UploadController
This commit is contained in:
2026-06-22 20:54:16 +01:00
parent b732c76aef
commit da6bf16d07
25 changed files with 511 additions and 765 deletions

View File

@@ -1,14 +1,19 @@
package com.ddf.vodsystem.services.media;
import com.ddf.vodsystem.dto.CommandOutput;
import com.ddf.vodsystem.dto.ProgressTracker;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CommandRunner {
private static final Pattern timePattern = Pattern.compile("out_time_ms=(\\d+)");
public static CommandOutput run(List<String> command, Consumer<String> onOutput) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
@@ -40,6 +45,14 @@ public class CommandRunner {
return run(command, null);
}
public static 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 CommandRunner() {
// Private constructor to prevent instantiation
}

View File

@@ -1,5 +1,6 @@
package com.ddf.vodsystem.services.media;
import com.ddf.vodsystem.dto.ProgressTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
@@ -50,7 +51,8 @@ public class StreamActionsService {
List<File> segments,
float trimOffset,
float duration,
File outputFile
File outputFile,
ProgressTracker progressTracker
) {
try {
String concatInput = segments.stream()
@@ -69,7 +71,7 @@ public class StreamActionsService {
logger.info("Saving section with ({} segments) to '{}'",
segments.size(), outputFile.getAbsolutePath());
CommandRunner.run(command, line -> logger.debug("{}", line));
CommandRunner.run(command, line -> CommandRunner.setProgress(line, progressTracker, duration));
return CompletableFuture.completedFuture(outputFile);
} catch (Exception e) {