diff --git a/client/src/main/java/ctbrec/ui/JavaFxRecording.java b/client/src/main/java/ctbrec/ui/JavaFxRecording.java
index e5ecf139..f74f666c 100644
--- a/client/src/main/java/ctbrec/ui/JavaFxRecording.java
+++ b/client/src/main/java/ctbrec/ui/JavaFxRecording.java
@@ -157,6 +157,7 @@ public class JavaFxRecording extends Recording {
setStatus(updated.getStatus());
setProgress(updated.getProgress());
setSizeInByte(updated.getSizeInByte());
+ setSingleFile(updated.isSingleFile());
}
@Override
@@ -188,6 +189,11 @@ public class JavaFxRecording extends Recording {
return delegate.isSingleFile();
}
+ @Override
+ public void setSingleFile(boolean singleFile) {
+ delegate.setSingleFile(singleFile);
+ }
+
@Override
public boolean isPinned() {
return delegate.isPinned();
diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java b/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java
index c48b41ad..1583606e 100644
--- a/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java
+++ b/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java
@@ -559,7 +559,6 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
}
private void onOpenDirectory(JavaFxRecording first) {
- String recordingsDir = Config.getInstance().getSettings().recordingsDir;
File tsFile = first.getAbsoluteFile();
new Thread(() -> DesktopIntegration.open(tsFile.getParent())).start();
}
diff --git a/common/pom.xml b/common/pom.xml
index eaf358d7..541444dc 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -50,6 +50,10 @@
com.google.guava
guava
+
+ commons-io
+ commons-io
+
org.openjfx
javafx-controls
diff --git a/common/src/main/java/ctbrec/NotImplementedExcetion.java b/common/src/main/java/ctbrec/NotImplementedExcetion.java
index 4fb3d3c9..9ecfda88 100644
--- a/common/src/main/java/ctbrec/NotImplementedExcetion.java
+++ b/common/src/main/java/ctbrec/NotImplementedExcetion.java
@@ -3,7 +3,7 @@ package ctbrec;
public class NotImplementedExcetion extends RuntimeException {
public NotImplementedExcetion() {
- super();
+ super("Not implemented");
}
public NotImplementedExcetion(String mesg) {
diff --git a/common/src/main/java/ctbrec/io/IoUtils.java b/common/src/main/java/ctbrec/io/IoUtils.java
index f3be9bbb..644e540b 100644
--- a/common/src/main/java/ctbrec/io/IoUtils.java
+++ b/common/src/main/java/ctbrec/io/IoUtils.java
@@ -17,12 +17,14 @@ public class IoUtils {
public static void deleteEmptyParents(File parent) throws IOException {
File recDir = new File(Config.getInstance().getSettings().recordingsDir);
- while (parent != null && parent.list() != null && parent.list().length == 0) {
+ while (parent != null && (parent.list() != null && parent.list().length == 0 || !parent.exists()) ) {
if (parent.equals(recDir)) {
return;
}
- LOG.debug("Deleting empty directory {}", parent.getAbsolutePath());
- Files.delete(parent.toPath());
+ if(parent.exists()) {
+ LOG.debug("Deleting empty directory {}", parent.getAbsolutePath());
+ Files.delete(parent.toPath());
+ }
parent = parent.getParentFile();
}
}
diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java
index 3afe4366..83a8e484 100644
--- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java
+++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java
@@ -165,7 +165,7 @@ public class NextGenLocalRecorder implements Recorder {
List postProcessors = config.getSettings().postProcessors;
for (PostProcessor postProcessor : postProcessors) {
LOG.debug("Running post-processor: {}", postProcessor.getName());
- postProcessor.postprocess(recording);
+ postProcessor.postprocess(recording, config);
}
setRecordingStatus(recording, State.FINISHED);
recordingManager.saveRecording(recording);
@@ -652,6 +652,7 @@ public class NextGenLocalRecorder implements Recorder {
Download download = other.getModel().createDownload();
download.init(Config.getInstance(), other.getModel(), other.getStartDate());
other.setDownload(download);
+ other.setPostProcessedFile(null);
submitPostProcessingJob(other);
return;
}
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java b/common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java
index d89d9bf4..b790a724 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java
@@ -29,7 +29,7 @@ public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPost
"${recordingsDir}"
};
- public String fillInPlaceHolders(String input, Recording rec) {
+ public String fillInPlaceHolders(String input, Recording rec, Config config) {
// @formatter:off
String output = input
.replace("${modelName}", ofNullable(rec.getModel().getName()).orElse("modelName"))
@@ -39,8 +39,8 @@ public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPost
.replace("${siteSanitizedName}", getSanitizedSiteName(rec))
.replace("${fileSuffix}", getFileSuffix(rec))
.replace("${epochSecond}", Long.toString(rec.getStartDate().getEpochSecond()))
- .replace("${modelNotes}", Config.getInstance().getModelNotes(rec.getModel()))
- .replace("${recordingsDir}", Config.getInstance().getSettings().recordingsDir)
+ .replace("${modelNotes}", config.getModelNotes(rec.getModel()))
+ .replace("${recordingsDir}", config.getSettings().recordingsDir)
;
output = replaceUtcDateTime(rec, output);
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java b/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java
index d77eefcf..4dbf0224 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java
@@ -2,12 +2,13 @@ package ctbrec.recorder.postprocessing;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.io.Files;
-
+import ctbrec.Config;
import ctbrec.Recording;
public class Copy extends AbstractPostProcessor {
@@ -20,20 +21,28 @@ public class Copy extends AbstractPostProcessor {
}
@Override
- public void postprocess(Recording rec) throws IOException, InterruptedException {
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
File orig = rec.getPostProcessedFile();
String copyFilename = getFilenameForCopy(orig);
File copy = new File(orig.getParentFile(), copyFilename);
LOG.info("Creating a copy {}", copy);
- Files.copy(rec.getPostProcessedFile(), copy);
+ if (orig.isFile()) {
+ Files.copy(rec.getPostProcessedFile().toPath(), copy.toPath());
+ } else {
+ FileUtils.copyDirectory(orig, copy, true);
+ }
rec.setPostProcessedFile(copy);
rec.getAssociatedFiles().add(copy.getCanonicalPath());
}
private String getFilenameForCopy(File orig) {
String filename = orig.getName();
- String name = filename.substring(0, filename.lastIndexOf('.'));
- String ext = filename.substring(filename.lastIndexOf('.') + 1);
- return name + "_copy." + ext;
+ if (orig.isFile()) {
+ String name = filename.substring(0, filename.lastIndexOf('.'));
+ String ext = filename.substring(filename.lastIndexOf('.') + 1);
+ return name + "_copy." + ext;
+ } else {
+ return filename + "_copy";
+ }
}
}
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/CreateContactSheet.java b/common/src/main/java/ctbrec/recorder/postprocessing/CreateContactSheet.java
new file mode 100644
index 00000000..2f090ad6
--- /dev/null
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/CreateContactSheet.java
@@ -0,0 +1,20 @@
+package ctbrec.recorder.postprocessing;
+
+import java.io.IOException;
+
+import ctbrec.Config;
+import ctbrec.NotImplementedExcetion;
+import ctbrec.Recording;
+
+public class CreateContactSheet extends AbstractPlaceholderAwarePostProcessor {
+
+ @Override
+ public String getName() {
+ return "create contact sheet";
+ }
+
+ @Override
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
+ throw new NotImplementedExcetion();
+ }
+}
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/CreateTimelineThumbs.java b/common/src/main/java/ctbrec/recorder/postprocessing/CreateTimelineThumbs.java
new file mode 100644
index 00000000..c17bcec1
--- /dev/null
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/CreateTimelineThumbs.java
@@ -0,0 +1,20 @@
+package ctbrec.recorder.postprocessing;
+
+import java.io.IOException;
+
+import ctbrec.Config;
+import ctbrec.NotImplementedExcetion;
+import ctbrec.Recording;
+
+public class CreateTimelineThumbs extends AbstractPlaceholderAwarePostProcessor {
+
+ @Override
+ public String getName() {
+ return "create timeline thumbnails";
+ }
+
+ @Override
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
+ throw new NotImplementedExcetion();
+ }
+}
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java b/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java
index 49337be3..71e1af8d 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java
@@ -5,6 +5,7 @@ import static ctbrec.io.IoUtils.*;
import java.io.IOException;
import java.nio.file.Files;
+import ctbrec.Config;
import ctbrec.Recording;
public class DeleteOriginal extends AbstractPostProcessor {
@@ -15,7 +16,7 @@ public class DeleteOriginal extends AbstractPostProcessor {
}
@Override
- public void postprocess(Recording rec) throws IOException, InterruptedException {
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
if (rec.getAbsoluteFile().isFile()) {
Files.deleteIfExists(rec.getAbsoluteFile().toPath());
deleteEmptyParents(rec.getAbsoluteFile().getParentFile());
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Move.java b/common/src/main/java/ctbrec/recorder/postprocessing/Move.java
index 36dbcbcf..40823ddd 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/Move.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/Move.java
@@ -3,13 +3,13 @@ import static ctbrec.io.IoUtils.*;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.io.Files;
-
+import ctbrec.Config;
import ctbrec.Recording;
public class Move extends AbstractPlaceholderAwarePostProcessor {
@@ -24,17 +24,17 @@ public class Move extends AbstractPlaceholderAwarePostProcessor {
}
@Override
- public void postprocess(Recording rec) throws IOException {
+ public void postprocess(Recording rec, Config config) throws IOException {
String pathTemplate = getConfig().getOrDefault(PATH_TEMPLATE, DEFAULT);
- String path = fillInPlaceHolders(pathTemplate, rec);
+ String path = fillInPlaceHolders(pathTemplate, rec, config);
File src = rec.getPostProcessedFile();
File target = new File(path, src.getName());
if (Objects.equals(src, target)) {
return;
}
LOG.info("Moving {} to {}", src.getName(), target.getParentFile().getCanonicalPath());
- Files.createParentDirs(target);
- Files.move(rec.getPostProcessedFile(), target);
+ Files.createDirectories(target.getParentFile().toPath());
+ Files.move(rec.getPostProcessedFile().toPath(), target.toPath());
rec.setPostProcessedFile(target);
if (Objects.equals(src, rec.getAbsoluteFile())) {
rec.setAbsoluteFile(target);
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/PostProcessor.java b/common/src/main/java/ctbrec/recorder/postprocessing/PostProcessor.java
index cc366520..9427655d 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/PostProcessor.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/PostProcessor.java
@@ -4,12 +4,13 @@ import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
+import ctbrec.Config;
import ctbrec.Recording;
public interface PostProcessor extends Serializable {
String getName();
- void postprocess(Recording rec) throws IOException, InterruptedException;
+ void postprocess(Recording rec, Config config) throws IOException, InterruptedException;
Map getConfig();
void setConfig(Map conf);
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/RemoveKeepFile.java b/common/src/main/java/ctbrec/recorder/postprocessing/RemoveKeepFile.java
new file mode 100644
index 00000000..1e76bd41
--- /dev/null
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/RemoveKeepFile.java
@@ -0,0 +1,20 @@
+package ctbrec.recorder.postprocessing;
+
+import java.io.IOException;
+
+import ctbrec.Config;
+import ctbrec.NotImplementedExcetion;
+import ctbrec.Recording;
+
+public class RemoveKeepFile extends AbstractPostProcessor {
+
+ @Override
+ public String getName() {
+ return "remove recording, but keep the files";
+ }
+
+ @Override
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
+ throw new NotImplementedExcetion();
+ }
+}
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Remux.java b/common/src/main/java/ctbrec/recorder/postprocessing/Remux.java
index cd7071bb..81142ef8 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/Remux.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/Remux.java
@@ -5,12 +5,15 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
+import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ctbrec.Config;
import ctbrec.OS;
import ctbrec.Recording;
+import ctbrec.io.IoUtils;
import ctbrec.io.StreamRedirectThread;
import ctbrec.recorder.download.ProcessExitedUncleanException;
@@ -27,15 +30,18 @@ public class Remux extends AbstractPostProcessor {
}
@Override
- public void postprocess(Recording rec) throws IOException, InterruptedException {
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
String fileExt = getConfig().get(FILE_EXT);
String[] args = getConfig().get(FFMPEG_ARGS).split(" ");
String[] argsPlusFile = new String[args.length + 3];
+ File inputFile = rec.getPostProcessedFile();
+ if (inputFile.isDirectory()) {
+ inputFile = new File(inputFile, "playlist.m3u8");
+ }
int i = 0;
argsPlusFile[i++] = "-i";
- argsPlusFile[i++] = rec.getPostProcessedFile().getAbsolutePath();
+ argsPlusFile[i++] = inputFile.getCanonicalPath();
System.arraycopy(args, 0, argsPlusFile, i, args.length);
- File inputFile = rec.getPostProcessedFile();
File remuxedFile = new File(rec.getPostProcessedFile().getAbsolutePath() + '.' + fileExt);
argsPlusFile[argsPlusFile.length - 1] = remuxedFile.getAbsolutePath();
String[] cmdline = OS.getFFmpegCommand(argsPlusFile);
@@ -43,16 +49,29 @@ public class Remux extends AbstractPostProcessor {
Process ffmpeg = Runtime.getRuntime().exec(cmdline, new String[0], rec.getPostProcessedFile().getParentFile());
setupLogging(ffmpeg, rec);
rec.setPostProcessedFile(remuxedFile);
- rec.setAbsoluteFile(remuxedFile);
- Files.deleteIfExists(inputFile.toPath());
+ if (inputFile.getName().equals("playlist.m3u8")) {
+ IoUtils.deleteDirectory(inputFile.getParentFile());
+ if (Objects.equals(inputFile.getParentFile(), rec.getAbsoluteFile())) {
+ rec.setAbsoluteFile(remuxedFile);
+ }
+ } else {
+ Files.deleteIfExists(inputFile.toPath());
+ if (Objects.equals(inputFile, rec.getAbsoluteFile())) {
+ rec.setAbsoluteFile(remuxedFile);
+ }
+ }
+ IoUtils.deleteEmptyParents(inputFile.getParentFile());
rec.getAssociatedFiles().remove(inputFile.getCanonicalPath());
rec.getAssociatedFiles().add(remuxedFile.getCanonicalPath());
+ rec.setSingleFile(true);
+ rec.setSizeInByte(remuxedFile.length());
}
private void setupLogging(Process ffmpeg, Recording rec) throws IOException, InterruptedException {
int exitCode = 1;
File video = rec.getPostProcessedFile();
File ffmpegLog = new File(video.getParentFile(), video.getName() + ".ffmpeg.log");
+ rec.getAssociatedFiles().add(ffmpegLog.getCanonicalPath());
try (FileOutputStream mergeLogStream = new FileOutputStream(ffmpegLog)) {
Thread stdout = new Thread(new StreamRedirectThread(ffmpeg.getInputStream(), mergeLogStream));
Thread stderr = new Thread(new StreamRedirectThread(ffmpeg.getErrorStream(), mergeLogStream));
@@ -67,6 +86,7 @@ public class Remux extends AbstractPostProcessor {
if (exitCode != 1) {
if (ffmpegLog.exists()) {
Files.delete(ffmpegLog.toPath());
+ rec.getAssociatedFiles().remove(ffmpegLog.getCanonicalPath());
}
} else {
rec.getAssociatedFiles().add(ffmpegLog.getAbsolutePath());
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java b/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java
index 441121e9..4789f029 100644
--- a/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java
@@ -1,13 +1,13 @@
package ctbrec.recorder.postprocessing;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.io.Files;
-
+import ctbrec.Config;
import ctbrec.Recording;
public class Rename extends AbstractPlaceholderAwarePostProcessor {
@@ -22,16 +22,16 @@ public class Rename extends AbstractPlaceholderAwarePostProcessor {
}
@Override
- public void postprocess(Recording rec) throws IOException {
+ public void postprocess(Recording rec, Config config) throws IOException {
String filenameTemplate = getConfig().getOrDefault(FILE_NAME_TEMPLATE, DEFAULT);
- String filename = fillInPlaceHolders(filenameTemplate, rec);
+ String filename = fillInPlaceHolders(filenameTemplate, rec, config);
File src = rec.getPostProcessedFile();
File target = new File(src.getParentFile(), filename);
if (Objects.equals(src, target)) {
return;
}
LOG.info("Renaming {} to {}", src.getName(), target.getName());
- Files.move(rec.getPostProcessedFile(), target);
+ Files.move(rec.getPostProcessedFile().toPath(), target.toPath());
rec.setPostProcessedFile(target);
if (Objects.equals(src, rec.getAbsoluteFile())) {
rec.setAbsoluteFile(target);
diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Script.java b/common/src/main/java/ctbrec/recorder/postprocessing/Script.java
new file mode 100644
index 00000000..a842867a
--- /dev/null
+++ b/common/src/main/java/ctbrec/recorder/postprocessing/Script.java
@@ -0,0 +1,21 @@
+package ctbrec.recorder.postprocessing;
+
+import java.io.IOException;
+
+import ctbrec.Config;
+import ctbrec.NotImplementedExcetion;
+import ctbrec.Recording;
+
+public class Script extends AbstractPlaceholderAwarePostProcessor {
+
+ @Override
+ public String getName() {
+ return "execute script";
+ }
+
+ @Override
+ public void postprocess(Recording rec, Config config) throws IOException, InterruptedException {
+ // TODO make it possible to choose, which placeholders to pass to the script
+ throw new NotImplementedExcetion();
+ }
+}
diff --git a/master/pom.xml b/master/pom.xml
index 40e91c83..f55c7825 100644
--- a/master/pom.xml
+++ b/master/pom.xml
@@ -103,6 +103,11 @@
guava
17.0
+
+ commons-io
+ commons-io
+ 2.8.0
+
junit
junit
diff --git a/server/src/main/java/ctbrec/recorder/server/HlsServlet.java b/server/src/main/java/ctbrec/recorder/server/HlsServlet.java
index 9498aede..72dd7858 100644
--- a/server/src/main/java/ctbrec/recorder/server/HlsServlet.java
+++ b/server/src/main/java/ctbrec/recorder/server/HlsServlet.java
@@ -40,8 +40,6 @@ public class HlsServlet extends AbstractCtbrecServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
-
String contextPath = getServletContext().getContextPath();
String request = req.getRequestURI().substring(contextPath.length() + 5);
Path recordingsDirPath = Paths.get(config.getSettings().recordingsDir).toAbsolutePath().normalize();
@@ -68,7 +66,10 @@ public class HlsServlet extends AbstractCtbrecServlet {
String id = request.split("/")[0];
Optional rec = getRecordingById(id);
if (rec.isPresent()) {
- File file = rec.get().getAbsoluteFile();
+ File path = rec.get().getAbsoluteFile();
+ if (!path.isFile()) {
+ path = new File(path, requestedFile.getName());
+ }
if (LOG.isTraceEnabled()) {
Enumeration headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
@@ -76,7 +77,7 @@ public class HlsServlet extends AbstractCtbrecServlet {
LOG.trace("{}: {}", header, req.getHeader(header));
}
}
- serveSegment(req, resp, file);
+ serveSegment(req, resp, path);
} else {
error404(req, resp);
return;