Implement scheduler input claiming

This commit is contained in:
JSLMPR 2026-07-10 01:38:33 +02:00
parent 702d768e33
commit 45092e23b0
3 changed files with 47 additions and 2 deletions

View File

@ -22,7 +22,7 @@ Note: the local machine's filesystem root is read-only in this workspace, so abs
2. [x] Add folder scheduler configuration properties.
3. [x] Create startup directory initialization for input, output, working, processed, and rejected folders.
4. [x] 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.
5. [x] Add repeat-prevention by moving selected inputs to a working folder before processing.
6. [ ] Add valid-video detection using extension filtering and `ffprobe`.
7. [ ] Add invalid-file handling that logs the reason and moves files to rejected storage.
8. [ ] Add FFmpeg clipping into `/output/clips/<video-name>/` using 8-second MP4/H.264/AAC segments.

View File

@ -11,6 +11,7 @@ import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
@ -38,7 +39,10 @@ public class FolderVideoScanScheduler {
try {
findNextCandidate().ifPresentOrElse(
candidate -> log.info("Selected folder video candidate for processing: {}", candidate.getFileName()),
candidate -> {
Path workingFile = moveToWorking(candidate);
log.info("Claimed folder video candidate for processing: {}", workingFile.getFileName());
},
() -> log.debug("No folder video candidate found in {}", properties.getInputDirectory())
);
} finally {
@ -46,6 +50,16 @@ public class FolderVideoScanScheduler {
}
}
Path moveToWorking(Path candidate) {
Path workingFile = Path.of(properties.getWorkingDirectory()).resolve(candidate.getFileName());
try {
return Files.move(candidate, workingFile, StandardCopyOption.ATOMIC_MOVE);
} catch (IOException ex) {
throw new IllegalStateException("Unable to move folder video candidate to working directory: "
+ candidate.getFileName(), ex);
}
}
Optional<Path> findNextCandidate() {
Path inputDirectory = Path.of(properties.getInputDirectory());
if (!Files.isDirectory(inputDirectory)) {

View File

@ -92,6 +92,8 @@ class FolderVideoScanSchedulerTest {
scheduler.scan();
assertFalse(((AtomicBoolean) scanningField.get(scheduler)).get());
assertFalse(Files.exists(tempDir.resolve("1.mp4")));
assertTrue(Files.exists(tempDir.resolve("working/1.mp4")));
}
@Test
@ -105,9 +107,38 @@ class FolderVideoScanSchedulerTest {
assertFalse(((AtomicBoolean) scanningField.get(scheduler)).get());
}
@Test
void claimedCandidateIsNotSelectedAgain() throws Exception {
Files.writeString(tempDir.resolve("1.mp4"), "video");
FolderVideoScanScheduler scheduler = scheduler(tempDir);
scheduler.scan();
assertTrue(scheduler.findNextCandidate().isEmpty());
assertEquals("video", Files.readString(tempDir.resolve("working/1.mp4")));
}
@Test
void failsWhenCandidateCannotBeMovedToWorkingDirectory() throws Exception {
Path candidate = Files.writeString(tempDir.resolve("1.mp4"), "video");
Files.writeString(tempDir.resolve("working"), "not a directory");
assertThrows(IllegalStateException.class, () -> scheduler(tempDir).moveToWorking(candidate));
assertTrue(Files.exists(candidate));
}
private FolderVideoScanScheduler scheduler(Path inputDirectory) {
VideoClippingProperties properties = new VideoClippingProperties();
properties.getFolderScheduler().setInputDirectory(inputDirectory.toString());
Path workingDirectory = tempDir.resolve("working");
if (!Files.exists(workingDirectory)) {
try {
Files.createDirectory(workingDirectory);
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
properties.getFolderScheduler().setWorkingDirectory(workingDirectory.toString());
return new FolderVideoScanScheduler(properties);
}
}