forked from jsl/video_editing_poc
• Implemented the next Input Folder Scheduler Plan milestone: startup directory initialization.
Added src/main/java/org/example/videoclips/folder/FolderSchedulerDirectoryInitializer.java, which creates the configured input, output, working, processed, and rejected directories when video-clipping.folder- scheduler.enabled=true. It stays inactive by default, so normal startup will not fail on machines where /input and /output cannot be created. Updated docs/input-folder-scheduler-plan.md to mark milestone 3 complete.
This commit is contained in:
parent
1cda571c30
commit
97cc4ff4e4
|
|
@ -19,8 +19,8 @@ Note: the local machine's filesystem root is read-only in this workspace, so abs
|
|||
## Milestones
|
||||
|
||||
1. [x] Create repository-local placeholder directories `input/source` and `output/clips`.
|
||||
2. [ ] Add folder scheduler configuration properties.
|
||||
3. [ ] Create startup directory initialization for input, output, working, processed, and rejected folders.
|
||||
2. [x] Add folder scheduler configuration properties.
|
||||
3. [x] Create startup directory initialization for input, output, working, processed, and rejected folders.
|
||||
4. [ ] Add deterministic scanner that picks one candidate video at a time.
|
||||
5. [ ] Add repeat-prevention by moving selected inputs to a working folder before processing.
|
||||
6. [ ] Add valid-video detection using extension filtering and `ffprobe`.
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ public class VideoClippingProperties {
|
|||
|
||||
private final Ffmpeg ffmpeg = new Ffmpeg();
|
||||
|
||||
private final FolderScheduler folderScheduler = new FolderScheduler();
|
||||
|
||||
private final Cleanup cleanup = new Cleanup();
|
||||
|
||||
private final Quotas quotas = new Quotas();
|
||||
|
|
@ -116,6 +118,10 @@ public class VideoClippingProperties {
|
|||
return ffmpeg;
|
||||
}
|
||||
|
||||
public FolderScheduler getFolderScheduler() {
|
||||
return folderScheduler;
|
||||
}
|
||||
|
||||
public Cleanup getCleanup() {
|
||||
return cleanup;
|
||||
}
|
||||
|
|
@ -335,6 +341,130 @@ public class VideoClippingProperties {
|
|||
}
|
||||
}
|
||||
|
||||
public static class FolderScheduler {
|
||||
private boolean enabled = false;
|
||||
|
||||
private String inputDirectory = "/input/source";
|
||||
|
||||
private String outputDirectory = "/output/clips";
|
||||
|
||||
private String processedDirectory = "/input/processed";
|
||||
|
||||
private String rejectedDirectory = "/input/rejected";
|
||||
|
||||
private String workingDirectory = "/input/working";
|
||||
|
||||
@Min(1000)
|
||||
private long pollIntervalMs = 5000;
|
||||
|
||||
@Min(1)
|
||||
private int segmentDurationSeconds = 8;
|
||||
|
||||
private String ffmpegBinary = "ffmpeg";
|
||||
|
||||
private String ffprobeBinary = "ffprobe";
|
||||
|
||||
private String outputContainer = "mp4";
|
||||
|
||||
private String exactPreset = "veryfast";
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getInputDirectory() {
|
||||
return inputDirectory;
|
||||
}
|
||||
|
||||
public void setInputDirectory(String inputDirectory) {
|
||||
this.inputDirectory = inputDirectory;
|
||||
}
|
||||
|
||||
public String getOutputDirectory() {
|
||||
return outputDirectory;
|
||||
}
|
||||
|
||||
public void setOutputDirectory(String outputDirectory) {
|
||||
this.outputDirectory = outputDirectory;
|
||||
}
|
||||
|
||||
public String getProcessedDirectory() {
|
||||
return processedDirectory;
|
||||
}
|
||||
|
||||
public void setProcessedDirectory(String processedDirectory) {
|
||||
this.processedDirectory = processedDirectory;
|
||||
}
|
||||
|
||||
public String getRejectedDirectory() {
|
||||
return rejectedDirectory;
|
||||
}
|
||||
|
||||
public void setRejectedDirectory(String rejectedDirectory) {
|
||||
this.rejectedDirectory = rejectedDirectory;
|
||||
}
|
||||
|
||||
public String getWorkingDirectory() {
|
||||
return workingDirectory;
|
||||
}
|
||||
|
||||
public void setWorkingDirectory(String workingDirectory) {
|
||||
this.workingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
public long getPollIntervalMs() {
|
||||
return pollIntervalMs;
|
||||
}
|
||||
|
||||
public void setPollIntervalMs(long pollIntervalMs) {
|
||||
this.pollIntervalMs = pollIntervalMs;
|
||||
}
|
||||
|
||||
public int getSegmentDurationSeconds() {
|
||||
return segmentDurationSeconds;
|
||||
}
|
||||
|
||||
public void setSegmentDurationSeconds(int segmentDurationSeconds) {
|
||||
this.segmentDurationSeconds = segmentDurationSeconds;
|
||||
}
|
||||
|
||||
public String getFfmpegBinary() {
|
||||
return ffmpegBinary;
|
||||
}
|
||||
|
||||
public void setFfmpegBinary(String ffmpegBinary) {
|
||||
this.ffmpegBinary = ffmpegBinary;
|
||||
}
|
||||
|
||||
public String getFfprobeBinary() {
|
||||
return ffprobeBinary;
|
||||
}
|
||||
|
||||
public void setFfprobeBinary(String ffprobeBinary) {
|
||||
this.ffprobeBinary = ffprobeBinary;
|
||||
}
|
||||
|
||||
public String getOutputContainer() {
|
||||
return outputContainer;
|
||||
}
|
||||
|
||||
public void setOutputContainer(String outputContainer) {
|
||||
this.outputContainer = outputContainer;
|
||||
}
|
||||
|
||||
public String getExactPreset() {
|
||||
return exactPreset;
|
||||
}
|
||||
|
||||
public void setExactPreset(String exactPreset) {
|
||||
this.exactPreset = exactPreset;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Quotas {
|
||||
@Min(0)
|
||||
private int maxActiveJobsPerTenant = 5;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package org.example.videoclips.folder;
|
||||
|
||||
import org.example.videoclips.config.VideoClippingProperties;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(name = "video-clipping.folder-scheduler.enabled", havingValue = "true")
|
||||
public class FolderSchedulerDirectoryInitializer implements ApplicationRunner {
|
||||
|
||||
private final VideoClippingProperties.FolderScheduler properties;
|
||||
|
||||
public FolderSchedulerDirectoryInitializer(VideoClippingProperties videoClippingProperties) {
|
||||
this.properties = videoClippingProperties.getFolderScheduler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
List.of(
|
||||
properties.getInputDirectory(),
|
||||
properties.getOutputDirectory(),
|
||||
properties.getWorkingDirectory(),
|
||||
properties.getProcessedDirectory(),
|
||||
properties.getRejectedDirectory()
|
||||
).forEach(this::createDirectory);
|
||||
}
|
||||
|
||||
private void createDirectory(String directory) {
|
||||
try {
|
||||
Files.createDirectories(Path.of(directory));
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException("Unable to create folder scheduler directory: " + directory, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,18 @@ video-clipping.ffmpeg.ffmpeg-binary=ffmpeg
|
|||
video-clipping.ffmpeg.input-directory=./tmp/ffmpeg-input
|
||||
video-clipping.ffmpeg.output-directory=./tmp/ffmpeg-output
|
||||
video-clipping.ffmpeg.cleanup-local-files=true
|
||||
video-clipping.folder-scheduler.enabled=false
|
||||
video-clipping.folder-scheduler.input-directory=/input/source
|
||||
video-clipping.folder-scheduler.output-directory=/output/clips
|
||||
video-clipping.folder-scheduler.processed-directory=/input/processed
|
||||
video-clipping.folder-scheduler.rejected-directory=/input/rejected
|
||||
video-clipping.folder-scheduler.working-directory=/input/working
|
||||
video-clipping.folder-scheduler.poll-interval-ms=5000
|
||||
video-clipping.folder-scheduler.segment-duration-seconds=8
|
||||
video-clipping.folder-scheduler.ffmpeg-binary=ffmpeg
|
||||
video-clipping.folder-scheduler.ffprobe-binary=ffprobe
|
||||
video-clipping.folder-scheduler.output-container=mp4
|
||||
video-clipping.folder-scheduler.exact-preset=veryfast
|
||||
video-clipping.quotas.max-active-jobs-per-tenant=5
|
||||
video-clipping.cleanup.enabled=true
|
||||
video-clipping.cleanup.local-artifact-poll-interval-ms=300000
|
||||
|
|
|
|||
Loading…
Reference in New Issue