RENAME VideoMetadata to ClipOptions and update related references

This commit is contained in:
2025-08-19 14:56:50 +02:00
parent 85c9d4348c
commit 9ebf69a9e7
11 changed files with 65 additions and 68 deletions

View File

@@ -12,6 +12,6 @@ post {
body:form-urlencoded { body:form-urlencoded {
startPoint: 10 startPoint: 10
endPoint: 40 duration: 40
title: best possible title title: best possible title
} }

View File

@@ -1,7 +1,7 @@
package com.ddf.vodsystem.controllers; package com.ddf.vodsystem.controllers;
import com.ddf.vodsystem.dto.JobStatus; import com.ddf.vodsystem.dto.JobStatus;
import com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import com.ddf.vodsystem.services.EditService; import com.ddf.vodsystem.services.EditService;
import com.ddf.vodsystem.dto.APIResponse; import com.ddf.vodsystem.dto.APIResponse;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -19,8 +19,8 @@ public class EditController {
} }
@PostMapping("edit/{uuid}") @PostMapping("edit/{uuid}")
public ResponseEntity<APIResponse<Void>> edit(@PathVariable("uuid") String uuid, @ModelAttribute VideoMetadata videoMetadata) { public ResponseEntity<APIResponse<Void>> edit(@PathVariable("uuid") String uuid, @ModelAttribute ClipOptions clipOptions) {
editService.edit(uuid, videoMetadata); editService.edit(uuid, clipOptions);
return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Editing started for UUID: " + uuid, null)); return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Editing started for UUID: " + uuid, null));
} }

View File

@@ -1,6 +1,6 @@
package com.ddf.vodsystem.controllers; package com.ddf.vodsystem.controllers;
import com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import com.ddf.vodsystem.dto.APIResponse; import com.ddf.vodsystem.dto.APIResponse;
import com.ddf.vodsystem.services.JobService; import com.ddf.vodsystem.services.JobService;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@@ -20,8 +20,8 @@ public class MetadataController {
} }
@GetMapping("/original/{uuid}") @GetMapping("/original/{uuid}")
public ResponseEntity<APIResponse<VideoMetadata>> getMetadata(@PathVariable String uuid) { public ResponseEntity<APIResponse<ClipOptions>> getMetadata(@PathVariable String uuid) {
VideoMetadata originalMetadata = jobService.getJob(uuid).getInputVideoMetadata(); ClipOptions originalMetadata = jobService.getJob(uuid).getInputClipOptions();
if (originalMetadata == null) { if (originalMetadata == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND) return ResponseEntity.status(HttpStatus.NOT_FOUND)
@@ -33,8 +33,8 @@ public class MetadataController {
} }
@GetMapping("/converted/{uuid}") @GetMapping("/converted/{uuid}")
public ResponseEntity<APIResponse<VideoMetadata>> getConvertedMetadata(@PathVariable String uuid) { public ResponseEntity<APIResponse<ClipOptions>> getConvertedMetadata(@PathVariable String uuid) {
VideoMetadata convertedMetadata = jobService.getJob(uuid).getOutputVideoMetadata(); ClipOptions convertedMetadata = jobService.getJob(uuid).getOutputClipOptions();
if (convertedMetadata == null) { if (convertedMetadata == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND) return ResponseEntity.status(HttpStatus.NOT_FOUND)

View File

@@ -3,11 +3,11 @@ package com.ddf.vodsystem.dto;
import lombok.Data; import lombok.Data;
@Data @Data
public class VideoMetadata { public class ClipOptions {
private String title; private String title;
private String description; private String description;
private Float startPoint; private Float startPoint;
private Float endPoint; private Float duration;
private Float fps; private Float fps;
private Integer width; private Integer width;
private Integer height; private Integer height;

View File

@@ -10,8 +10,8 @@ public class Job {
private File outputFile; private File outputFile;
// configs // configs
private VideoMetadata inputVideoMetadata; private ClipOptions inputClipOptions;
private VideoMetadata outputVideoMetadata = new VideoMetadata(); private ClipOptions outputClipOptions = new ClipOptions();
// job status // job status
private JobStatus status = new JobStatus(); private JobStatus status = new JobStatus();
@@ -19,10 +19,10 @@ public class Job {
public Job(String uuid, public Job(String uuid,
File inputFile, File inputFile,
File outputFile, File outputFile,
VideoMetadata inputVideoMetadata) { ClipOptions inputClipOptions) {
this.uuid = uuid; this.uuid = uuid;
this.inputFile = inputFile; this.inputFile = inputFile;
this.outputFile = outputFile; this.outputFile = outputFile;
this.inputVideoMetadata = inputVideoMetadata; this.inputClipOptions = inputClipOptions;
} }
} }

View File

@@ -1,7 +1,7 @@
package com.ddf.vodsystem.services; package com.ddf.vodsystem.services;
import com.ddf.vodsystem.dto.ProgressTracker; import com.ddf.vodsystem.dto.ProgressTracker;
import com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import com.ddf.vodsystem.entities.*; import com.ddf.vodsystem.entities.*;
import java.io.File; import java.io.File;
@@ -60,8 +60,8 @@ public class ClipService {
* @throws IOException if an I/O error occurs during file processing. * @throws IOException if an I/O error occurs during file processing.
* @throws InterruptedException if the thread is interrupted during processing. * @throws InterruptedException if the thread is interrupted during processing.
*/ */
public void create(VideoMetadata inputMetadata, public void create(ClipOptions inputMetadata,
VideoMetadata outputMetadata, ClipOptions outputMetadata,
File inputFile, File inputFile,
File outputFile, File outputFile,
ProgressTracker progress) ProgressTracker progress)
@@ -158,16 +158,16 @@ public class ClipService {
return user.get().getId().equals(clip.getUser().getId()); return user.get().getId().equals(clip.getUser().getId());
} }
private void persistClip(VideoMetadata videoMetadata, private void persistClip(ClipOptions clipOptions,
User user, User user,
File tempFile, File tempFile,
String fileName) { String fileName) {
// Move clip from temp to output directory // Move clip from temp to output directory
File clipFile = directoryService.getUserClipsFile(user.getId(), fileName); File clipFile = directoryService.getUserClipsFile(user.getId(), fileName);
File thumbnailFile = directoryService.getUserThumbnailsFile(user.getId(), fileName + ".png"); File thumbnailFile = directoryService.getUserThumbnailsFile(user.getId(), fileName + ".png");
directoryService.cutFile(tempFile, clipFile); directoryService.cutFile(tempFile, clipFile);
VideoMetadata clipMetadata; ClipOptions clipMetadata;
try { try {
clipMetadata = metadataService.getVideoMetadata(clipFile).get(); clipMetadata = metadataService.getVideoMetadata(clipFile).get();
} catch (InterruptedException | ExecutionException e) { } catch (InterruptedException | ExecutionException e) {
@@ -186,13 +186,13 @@ public class ClipService {
// Save clip to database // Save clip to database
Clip clip = new Clip(); Clip clip = new Clip();
clip.setUser(user); clip.setUser(user);
clip.setTitle(videoMetadata.getTitle() != null ? videoMetadata.getTitle() : "Untitled Clip"); clip.setTitle(clipOptions.getTitle() != null ? clipOptions.getTitle() : "Untitled Clip");
clip.setDescription(videoMetadata.getDescription() != null ? videoMetadata.getDescription() : ""); clip.setDescription(clipOptions.getDescription() != null ? clipOptions.getDescription() : "");
clip.setCreatedAt(LocalDateTime.now()); clip.setCreatedAt(LocalDateTime.now());
clip.setWidth(clipMetadata.getWidth()); clip.setWidth(clipMetadata.getWidth());
clip.setHeight(clipMetadata.getHeight()); clip.setHeight(clipMetadata.getHeight());
clip.setFps(clipMetadata.getFps()); clip.setFps(clipMetadata.getFps());
clip.setDuration(clipMetadata.getEndPoint() - clipMetadata.getStartPoint()); clip.setDuration(clipMetadata.getDuration() - clipMetadata.getStartPoint());
clip.setFileSize(clipMetadata.getFileSize()); clip.setFileSize(clipMetadata.getFileSize());
clip.setVideoPath(clipFile.getPath()); clip.setVideoPath(clipFile.getPath());
clip.setThumbnailPath(thumbnailFile.getPath()); clip.setThumbnailPath(thumbnailFile.getPath());

View File

@@ -1,7 +1,7 @@
package com.ddf.vodsystem.services; package com.ddf.vodsystem.services;
import com.ddf.vodsystem.dto.JobStatus; import com.ddf.vodsystem.dto.JobStatus;
import com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import com.ddf.vodsystem.dto.Job; import com.ddf.vodsystem.dto.Job;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -14,10 +14,10 @@ public class EditService {
this.jobService = jobService; this.jobService = jobService;
} }
public void edit(String uuid, VideoMetadata videoMetadata) { public void edit(String uuid, ClipOptions clipOptions) {
Job job = jobService.getJob(uuid); Job job = jobService.getJob(uuid);
validateClipConfig(videoMetadata); validateClipConfig(clipOptions);
job.setOutputVideoMetadata(videoMetadata); job.setOutputClipOptions(clipOptions);
} }
public void process(String uuid) { public void process(String uuid) {
@@ -35,13 +35,13 @@ public class EditService {
return job.getStatus(); return job.getStatus();
} }
private void validateClipConfig(VideoMetadata videoMetadata) { private void validateClipConfig(ClipOptions clipOptions) {
Float start = videoMetadata.getStartPoint(); Float start = clipOptions.getStartPoint();
Float end = videoMetadata.getEndPoint(); Float end = clipOptions.getDuration();
Float fileSize = videoMetadata.getFileSize(); Float fileSize = clipOptions.getFileSize();
Integer width = videoMetadata.getWidth(); Integer width = clipOptions.getWidth();
Integer height = videoMetadata.getHeight(); Integer height = clipOptions.getHeight();
Float fps = videoMetadata.getFps(); Float fps = clipOptions.getFps();
if (start != null && start < 0) { if (start != null && start < 0) {
throw new IllegalArgumentException("Start point cannot be negative"); throw new IllegalArgumentException("Start point cannot be negative");

View File

@@ -72,7 +72,7 @@ public class JobService {
tempFile, tempFile,
job.getInputFile(), job.getInputFile(),
job.getStatus().getConversion(), job.getStatus().getConversion(),
job.getInputVideoMetadata().getEndPoint()) job.getInputClipOptions().getDuration())
.thenRun(() -> { .thenRun(() -> {
job.getStatus().getConversion().markComplete(); job.getStatus().getConversion().markComplete();
directoryService.deleteFile(tempFile); directoryService.deleteFile(tempFile);
@@ -94,8 +94,8 @@ public class JobService {
try { try {
clipService.create( clipService.create(
job.getInputVideoMetadata(), job.getInputClipOptions(),
job.getOutputVideoMetadata(), job.getOutputClipOptions(),
job.getInputFile(), job.getInputFile(),
job.getOutputFile(), job.getOutputFile(),
job.getStatus().getProcess() job.getStatus().getProcess()

View File

@@ -1,7 +1,7 @@
package com.ddf.vodsystem.services; package com.ddf.vodsystem.services;
import com.ddf.vodsystem.dto.Job; import com.ddf.vodsystem.dto.Job;
import com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import com.ddf.vodsystem.exceptions.FFMPEGException; import com.ddf.vodsystem.exceptions.FFMPEGException;
import com.ddf.vodsystem.services.media.MetadataService; import com.ddf.vodsystem.services.media.MetadataService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -46,8 +46,8 @@ public class UploadService {
// add job // add job
logger.info("Uploaded file and creating job with UUID: {}", uuid); logger.info("Uploaded file and creating job with UUID: {}", uuid);
VideoMetadata videoMetadata = getMetadataWithTimeout(inputFile); ClipOptions clipOptions = getMetadataWithTimeout(inputFile);
Job job = new Job(uuid, inputFile, outputFile, videoMetadata); Job job = new Job(uuid, inputFile, outputFile, clipOptions);
jobService.add(job); jobService.add(job);
return uuid; return uuid;
@@ -61,7 +61,7 @@ public class UploadService {
return Base64.getUrlEncoder().withoutPadding().encodeToString(bb.array()); return Base64.getUrlEncoder().withoutPadding().encodeToString(bb.array());
} }
private VideoMetadata getMetadataWithTimeout(File file) { private ClipOptions getMetadataWithTimeout(File file) {
try { try {
return metadataService.getVideoMetadata(file).get(5, TimeUnit.SECONDS); return metadataService.getVideoMetadata(file).get(5, TimeUnit.SECONDS);
} catch (ExecutionException | TimeoutException | InterruptedException e) { } catch (ExecutionException | TimeoutException | InterruptedException e) {

View File

@@ -2,7 +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 com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
@@ -28,15 +28,13 @@ public class CompressionService {
@Async("ffmpegTaskExecutor") @Async("ffmpegTaskExecutor")
public CompletableFuture<CommandOutput> compress(File inputFile, public CompletableFuture<CommandOutput> compress(File inputFile,
File outputFile, File outputFile,
VideoMetadata videoMetadata, ClipOptions clipOptions,
ProgressTracker progress ProgressTracker progress
) throws IOException, InterruptedException { ) throws IOException, InterruptedException {
logger.info("Compressing video from {} to {}", inputFile.getAbsolutePath(), outputFile.getAbsolutePath()); logger.info("Compressing video from {} to {}", inputFile.getAbsolutePath(), outputFile.getAbsolutePath());
float length = videoMetadata.getEndPoint() - videoMetadata.getStartPoint(); List<String> command = buildCommand(inputFile, outputFile, clipOptions);
List<String> command = buildCommand(inputFile, outputFile, videoMetadata); CommandOutput result = CommandRunner.run(command, line -> setProgress(line, progress, clipOptions.getDuration()));
CommandOutput result = CommandRunner.run(command, line -> setProgress(line, progress, length));
progress.markComplete(); progress.markComplete();
return CompletableFuture.completedFuture(result); return CompletableFuture.completedFuture(result);
@@ -110,22 +108,21 @@ public class CompressionService {
return command; return command;
} }
private List<String> buildCommand(File inputFile, File outputFile, VideoMetadata videoMetadata) { private List<String> buildCommand(File inputFile, File outputFile, ClipOptions clipOptions) {
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
command.add("ffmpeg"); command.add("ffmpeg");
command.add("-progress"); command.add("-progress");
command.add("pipe:1"); command.add("pipe:1");
command.add("-y"); command.add("-y");
Float length = videoMetadata.getEndPoint() - videoMetadata.getStartPoint(); command.addAll(buildInputs(inputFile, clipOptions.getStartPoint(), clipOptions.getDuration()));
command.addAll(buildInputs(inputFile, videoMetadata.getStartPoint(), length));
if (videoMetadata.getFps() != null || videoMetadata.getWidth() != null || videoMetadata.getHeight() != null) { if (clipOptions.getFps() != null || clipOptions.getWidth() != null || clipOptions.getHeight() != null) {
command.addAll(buildFilters(videoMetadata.getFps(), videoMetadata.getWidth(), videoMetadata.getHeight())); command.addAll(buildFilters(clipOptions.getFps(), clipOptions.getWidth(), clipOptions.getHeight()));
} }
if (videoMetadata.getFileSize() != null) { if (clipOptions.getFileSize() != null) {
command.addAll(buildBitrate(length, videoMetadata.getFileSize())); command.addAll(buildBitrate(clipOptions.getDuration(), clipOptions.getFileSize()));
} }
// Output file // Output file

View File

@@ -1,7 +1,7 @@
package com.ddf.vodsystem.services.media; package com.ddf.vodsystem.services.media;
import com.ddf.vodsystem.dto.CommandOutput; import com.ddf.vodsystem.dto.CommandOutput;
import com.ddf.vodsystem.dto.VideoMetadata; import com.ddf.vodsystem.dto.ClipOptions;
import com.ddf.vodsystem.exceptions.FFMPEGException; import com.ddf.vodsystem.exceptions.FFMPEGException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@@ -21,7 +21,7 @@ public class MetadataService {
private static final Logger logger = LoggerFactory.getLogger(MetadataService.class); private static final Logger logger = LoggerFactory.getLogger(MetadataService.class);
@Async("ffmpegTaskExecutor") @Async("ffmpegTaskExecutor")
public Future<VideoMetadata> getVideoMetadata(File file) { public Future<ClipOptions> getVideoMetadata(File file) {
logger.info("Getting metadata for file {}", file.getAbsolutePath()); logger.info("Getting metadata for file {}", file.getAbsolutePath());
List<String> command = List.of( List<String> command = List.of(
@@ -51,24 +51,24 @@ public class MetadataService {
} }
} }
public void normalizeVideoMetadata(VideoMetadata inputFileMetadata, VideoMetadata outputFileMetadata) { public void normalizeVideoMetadata(ClipOptions inputFileMetadata, ClipOptions outputFileMetadata) {
if (outputFileMetadata.getStartPoint() == null) { if (outputFileMetadata.getStartPoint() == null) {
outputFileMetadata.setStartPoint(0f); outputFileMetadata.setStartPoint(0f);
} }
if (outputFileMetadata.getEndPoint() == null) { if (outputFileMetadata.getDuration() == null) {
outputFileMetadata.setEndPoint(inputFileMetadata.getEndPoint()); outputFileMetadata.setDuration(inputFileMetadata.getDuration());
} }
} }
private VideoMetadata parseVideoMetadata(JsonNode node) { private ClipOptions parseVideoMetadata(JsonNode node) {
VideoMetadata metadata = new VideoMetadata(); ClipOptions metadata = new ClipOptions();
metadata.setStartPoint(0f); metadata.setStartPoint(0f);
JsonNode streamNode = extractStreamNode(node); JsonNode streamNode = extractStreamNode(node);
metadata.setEndPoint(extractDuration(streamNode)); metadata.setDuration(extractDuration(streamNode));
metadata.setWidth(getWidth(streamNode)); metadata.setWidth(getWidth(streamNode));
metadata.setHeight(getHeight(streamNode)); metadata.setHeight(getHeight(streamNode));
metadata.setFps(extractFps(streamNode)); metadata.setFps(extractFps(streamNode));
@@ -125,9 +125,9 @@ public class MetadataService {
throw new FFMPEGException("ffprobe file size missing"); throw new FFMPEGException("ffprobe file size missing");
} }
private void extractEndPointFromFormat(VideoMetadata metadata, JsonNode formatNode) { private void extractEndPointFromFormat(ClipOptions metadata, JsonNode formatNode) {
if (formatNode != null && formatNode.has("duration") && metadata.getEndPoint() == null) { if (formatNode != null && formatNode.has("duration") && metadata.getDuration() == null) {
metadata.setEndPoint(Float.parseFloat(formatNode.get("duration").asText())); metadata.setDuration(Float.parseFloat(formatNode.get("duration").asText()));
} }
} }