diff --git a/client/src/main/java/ctbrec/ui/settings/MoverPaneFactory.java b/client/src/main/java/ctbrec/ui/settings/MoverPaneFactory.java new file mode 100644 index 00000000..c45bc1c9 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/settings/MoverPaneFactory.java @@ -0,0 +1,24 @@ +package ctbrec.ui.settings; + +import ctbrec.recorder.postprocessing.Move; +import ctbrec.recorder.postprocessing.PostProcessor; +import ctbrec.ui.settings.api.Category; +import ctbrec.ui.settings.api.Preferences; +import ctbrec.ui.settings.api.Setting; +import javafx.beans.property.SimpleStringProperty; + +public class MoverPaneFactory extends AbstractPostProcessingPaneFactory { + + @Override + public Preferences doCreatePostProcessorPane(PostProcessor pp) { + SimpleStringProperty pathTemplate = new SimpleStringProperty(null, Move.PATH_TEMPLATE, pp.getConfig().getOrDefault(Move.PATH_TEMPLATE, Move.DEFAULT)); + properties.add(pathTemplate); + + return Preferences.of(new MapPreferencesStorage(), + Category.of(pp.getName(), + Setting.of("Directory", pathTemplate) + ) + ); + } + +} diff --git a/client/src/main/java/ctbrec/ui/settings/PostProcessingDialogFactory.java b/client/src/main/java/ctbrec/ui/settings/PostProcessingDialogFactory.java index 094f4c8c..eccad370 100644 --- a/client/src/main/java/ctbrec/ui/settings/PostProcessingDialogFactory.java +++ b/client/src/main/java/ctbrec/ui/settings/PostProcessingDialogFactory.java @@ -7,9 +7,10 @@ import java.util.Map; import java.util.Optional; import ctbrec.Config; +import ctbrec.recorder.postprocessing.Move; import ctbrec.recorder.postprocessing.PostProcessor; -import ctbrec.recorder.postprocessing.Remuxer; -import ctbrec.recorder.postprocessing.Renamer; +import ctbrec.recorder.postprocessing.Remux; +import ctbrec.recorder.postprocessing.Rename; import ctbrec.ui.controls.Dialogs; import ctbrec.ui.settings.api.Preferences; import javafx.collections.ObservableList; @@ -20,8 +21,9 @@ public class PostProcessingDialogFactory { static Map, Class> ppToDialogMap = new HashMap<>(); static { - ppToDialogMap.put(Remuxer.class, RemuxerPaneFactory.class); - ppToDialogMap.put(Renamer.class, RenamerPaneFactory.class); + ppToDialogMap.put(Remux.class, RemuxerPaneFactory.class); + ppToDialogMap.put(Rename.class, RenamerPaneFactory.class); + ppToDialogMap.put(Move.class, MoverPaneFactory.class); } private PostProcessingDialogFactory() { diff --git a/client/src/main/java/ctbrec/ui/settings/PostProcessingStepPanel.java b/client/src/main/java/ctbrec/ui/settings/PostProcessingStepPanel.java index 91e5d367..05a18f92 100644 --- a/client/src/main/java/ctbrec/ui/settings/PostProcessingStepPanel.java +++ b/client/src/main/java/ctbrec/ui/settings/PostProcessingStepPanel.java @@ -7,9 +7,11 @@ import java.util.Optional; import ctbrec.Config; import ctbrec.recorder.postprocessing.Copy; +import ctbrec.recorder.postprocessing.DeleteOriginal; +import ctbrec.recorder.postprocessing.Move; import ctbrec.recorder.postprocessing.PostProcessor; -import ctbrec.recorder.postprocessing.Remuxer; -import ctbrec.recorder.postprocessing.Renamer; +import ctbrec.recorder.postprocessing.Remux; +import ctbrec.recorder.postprocessing.Rename; import ctbrec.ui.controls.Dialogs; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; @@ -28,7 +30,14 @@ public class PostProcessingStepPanel extends GridPane { private Config config; - private static final Class[] POST_PROCESSOR_CLASSES = new Class[] { Copy.class, Remuxer.class, Renamer.class }; + + private static final Class[] POST_PROCESSOR_CLASSES = new Class[] { // @formatter: off + Copy.class, + Remux.class, + Rename.class, + Move.class, + DeleteOriginal.class + }; // @formatter: on ListView stepListView; ObservableList stepList; diff --git a/client/src/main/java/ctbrec/ui/settings/RemuxerPaneFactory.java b/client/src/main/java/ctbrec/ui/settings/RemuxerPaneFactory.java index 886182ad..64a9c0fb 100644 --- a/client/src/main/java/ctbrec/ui/settings/RemuxerPaneFactory.java +++ b/client/src/main/java/ctbrec/ui/settings/RemuxerPaneFactory.java @@ -1,7 +1,7 @@ package ctbrec.ui.settings; import ctbrec.recorder.postprocessing.PostProcessor; -import ctbrec.recorder.postprocessing.Remuxer; +import ctbrec.recorder.postprocessing.Remux; import ctbrec.ui.settings.api.Category; import ctbrec.ui.settings.api.Preferences; import ctbrec.ui.settings.api.Setting; @@ -11,8 +11,8 @@ public class RemuxerPaneFactory extends AbstractPostProcessingPaneFactory { @Override public Preferences doCreatePostProcessorPane(PostProcessor pp) { - SimpleStringProperty ffmpegParams = new SimpleStringProperty(null, Remuxer.FFMPEG_ARGS, pp.getConfig().getOrDefault(Remuxer.FFMPEG_ARGS, "-c:v copy -c:a copy -movflags faststart -y -f mp4")); - SimpleStringProperty fileExt = new SimpleStringProperty(null, Remuxer.FILE_EXT, pp.getConfig().getOrDefault(Remuxer.FILE_EXT, "mp4")); + SimpleStringProperty ffmpegParams = new SimpleStringProperty(null, Remux.FFMPEG_ARGS, pp.getConfig().getOrDefault(Remux.FFMPEG_ARGS, "-c:v copy -c:a copy -movflags faststart -y -f mp4")); + SimpleStringProperty fileExt = new SimpleStringProperty(null, Remux.FILE_EXT, pp.getConfig().getOrDefault(Remux.FILE_EXT, "mp4")); properties.add(ffmpegParams); properties.add(fileExt); diff --git a/client/src/main/java/ctbrec/ui/settings/RenamerPaneFactory.java b/client/src/main/java/ctbrec/ui/settings/RenamerPaneFactory.java index 2140b75a..4c887403 100644 --- a/client/src/main/java/ctbrec/ui/settings/RenamerPaneFactory.java +++ b/client/src/main/java/ctbrec/ui/settings/RenamerPaneFactory.java @@ -1,7 +1,7 @@ package ctbrec.ui.settings; import ctbrec.recorder.postprocessing.PostProcessor; -import ctbrec.recorder.postprocessing.Renamer; +import ctbrec.recorder.postprocessing.Rename; import ctbrec.ui.settings.api.Category; import ctbrec.ui.settings.api.Preferences; import ctbrec.ui.settings.api.Setting; @@ -11,7 +11,7 @@ public class RenamerPaneFactory extends AbstractPostProcessingPaneFactory { @Override public Preferences doCreatePostProcessorPane(PostProcessor pp) { - SimpleStringProperty fileTemplate = new SimpleStringProperty(null, Renamer.FILE_NAME_TEMPLATE, pp.getConfig().getOrDefault(Renamer.FILE_NAME_TEMPLATE, Renamer.DEFAULT)); + SimpleStringProperty fileTemplate = new SimpleStringProperty(null, Rename.FILE_NAME_TEMPLATE, pp.getConfig().getOrDefault(Rename.FILE_NAME_TEMPLATE, Rename.DEFAULT)); properties.add(fileTemplate); return Preferences.of(new MapPreferencesStorage(), diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java index 2521d99b..6c4d6613 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java @@ -228,7 +228,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { @Override public String get() { - String modelNotes = Config.getInstance().getSettings().modelNotes.getOrDefault(m.getUrl(), ""); + String modelNotes = Config.getInstance().getModelNotes(m); return modelNotes; } }; diff --git a/common/src/main/java/ctbrec/Config.java b/common/src/main/java/ctbrec/Config.java index c18b3a96..fa08993c 100644 --- a/common/src/main/java/ctbrec/Config.java +++ b/common/src/main/java/ctbrec/Config.java @@ -193,4 +193,8 @@ public class Config { } return context; } + + public String getModelNotes(Model m) { + return Config.getInstance().getSettings().modelNotes.getOrDefault(m.getUrl(), ""); + } } diff --git a/common/src/main/java/ctbrec/io/IoUtils.java b/common/src/main/java/ctbrec/io/IoUtils.java new file mode 100644 index 00000000..f3be9bbb --- /dev/null +++ b/common/src/main/java/ctbrec/io/IoUtils.java @@ -0,0 +1,51 @@ +package ctbrec.io; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ctbrec.Config; + +public class IoUtils { + + private static final Logger LOG = LoggerFactory.getLogger(IoUtils.class); + + private 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) { + if (parent.equals(recDir)) { + return; + } + LOG.debug("Deleting empty directory {}", parent.getAbsolutePath()); + Files.delete(parent.toPath()); + parent = parent.getParentFile(); + } + } + + public static void deleteDirectory(File directory) throws IOException { + if (!directory.exists()) { + return; + } + + File[] files = directory.listFiles(); + boolean deletedAllFiles = true; + for (File file : files) { + try { + LOG.trace("Deleting {}", file.getAbsolutePath()); + Files.delete(file.toPath()); + } catch (Exception e) { + deletedAllFiles = false; + LOG.debug("Couldn't delete {}", file, e); + } + } + + if (!deletedAllFiles) { + throw new IOException("Couldn't delete all files in " + directory); + } + } +} diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java index d410edee..3afe4366 100644 --- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java @@ -164,6 +164,7 @@ public class NextGenLocalRecorder implements Recorder { recording.postprocess(); List postProcessors = config.getSettings().postProcessors; for (PostProcessor postProcessor : postProcessors) { + LOG.debug("Running post-processor: {}", postProcessor.getName()); postProcessor.postprocess(recording); } setRecordingStatus(recording, State.FINISHED); diff --git a/common/src/main/java/ctbrec/recorder/RecordingManager.java b/common/src/main/java/ctbrec/recorder/RecordingManager.java index 90072924..69735f11 100644 --- a/common/src/main/java/ctbrec/recorder/RecordingManager.java +++ b/common/src/main/java/ctbrec/recorder/RecordingManager.java @@ -1,6 +1,7 @@ package ctbrec.recorder; import static ctbrec.Recording.State.*; +import static ctbrec.io.IoUtils.*; import static java.nio.charset.StandardCharsets.*; import static java.nio.file.StandardOpenOption.*; @@ -142,8 +143,10 @@ public class RecordingManager { File f = new File(associated); if (f.isFile()) { Files.delete(f.toPath()); + deleteEmptyParents(f.getParentFile()); } else { deleteDirectory(f); + deleteEmptyParents(f); } } @@ -202,40 +205,6 @@ public class RecordingManager { } } - 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) { - if (parent.equals(recDir)) { - return; - } - LOG.debug("Deleting empty directory {}", parent.getAbsolutePath()); - Files.delete(parent.toPath()); - parent = parent.getParentFile(); - } - } - - private void deleteDirectory(File directory) throws IOException { - if (!directory.exists()) { - return; - } - - File[] files = directory.listFiles(); - boolean deletedAllFiles = true; - for (File file : files) { - try { - LOG.trace("Deleting {}", file.getAbsolutePath()); - Files.delete(file.toPath()); - } catch (Exception e) { - deletedAllFiles = false; - LOG.debug("Couldn't delete {}", file, e); - } - } - - if (!deletedAllFiles) { - throw new IOException("Couldn't delete all files in " + directory); - } - } - public void pin(Recording recording) throws IOException { recordingsLock.lock(); try { diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Renamer.java b/common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java similarity index 65% rename from common/src/main/java/ctbrec/recorder/postprocessing/Renamer.java rename to common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java index b542cb24..d89d9bf4 100644 --- a/common/src/main/java/ctbrec/recorder/postprocessing/Renamer.java +++ b/common/src/main/java/ctbrec/recorder/postprocessing/AbstractPlaceholderAwarePostProcessor.java @@ -1,8 +1,7 @@ package ctbrec.recorder.postprocessing; + import static java.util.Optional.*; -import java.io.File; -import java.io.IOException; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -10,18 +9,10 @@ import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.io.Files; - +import ctbrec.Config; import ctbrec.Recording; -public class Renamer extends AbstractPostProcessor { - - private static final Logger LOG = LoggerFactory.getLogger(Renamer.class); - public static final String FILE_NAME_TEMPLATE = "filename.template"; - public static final String DEFAULT = "${modelSanitizedName}_${localDateTime}.${fileSuffix}"; +public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPostProcessor { @SuppressWarnings("unused") private String[] placeHolders = { @@ -34,18 +25,13 @@ public class Renamer extends AbstractPostProcessor { "${localDateTime}", "${epochSecond}", "${fileSuffix}", - "${modelNotes}" + "${modelNotes}", + "${recordingsDir}" }; - @Override - public String getName() { - return "rename"; - } - - @Override - public void postprocess(Recording rec) throws IOException { - String filenameTemplate = getConfig().getOrDefault(FILE_NAME_TEMPLATE, DEFAULT); - String filename = filenameTemplate + public String fillInPlaceHolders(String input, Recording rec) { + // @formatter:off + String output = input .replace("${modelName}", ofNullable(rec.getModel().getName()).orElse("modelName")) .replace("${modelDisplayName}", ofNullable(rec.getModel().getDisplayName()).orElse("displayName")) .replace("${modelSanitizedName}", ofNullable(rec.getModel().getSanitizedNamed()).orElse("sanitizedName")) @@ -53,17 +39,15 @@ public class Renamer extends AbstractPostProcessor { .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) ; - filename = replaceUtcDateTime(rec, filename); - filename = replaceLocalDateTime(rec, filename); + output = replaceUtcDateTime(rec, output); + output = replaceLocalDateTime(rec, output); - File src = rec.getPostProcessedFile(); - File target = new File(src.getParentFile(), filename); - LOG.info("Renaming {} to {}", src.getName(), target.getName()); - Files.move(rec.getPostProcessedFile(), target); - rec.setPostProcessedFile(target); - rec.getAssociatedFiles().add(target.getAbsolutePath()); + return output; + // @formatter:on } private String replaceUtcDateTime(Recording rec, String filename) { @@ -99,17 +83,8 @@ public class Renamer extends AbstractPostProcessor { return filename.substring(filename.lastIndexOf('.') + 1); } - private CharSequence getSanitizedSiteName(Recording rec) { return rec.getModel().getSite().getName().replace(' ', '_').replace('\\', '_').replace('/', '_'); } - @Override - public String toString() { - String s = getName(); - if (getConfig().containsKey(FILE_NAME_TEMPLATE)) { - s += " [" + getConfig().get(FILE_NAME_TEMPLATE) + ']'; - } - return s; - } } diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java b/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java index 88dcf452..d77eefcf 100644 --- a/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java +++ b/common/src/main/java/ctbrec/recorder/postprocessing/Copy.java @@ -27,7 +27,7 @@ public class Copy extends AbstractPostProcessor { LOG.info("Creating a copy {}", copy); Files.copy(rec.getPostProcessedFile(), copy); rec.setPostProcessedFile(copy); - rec.getAssociatedFiles().add(copy.getAbsolutePath()); + rec.getAssociatedFiles().add(copy.getCanonicalPath()); } private String getFilenameForCopy(File orig) { diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java b/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java new file mode 100644 index 00000000..49337be3 --- /dev/null +++ b/common/src/main/java/ctbrec/recorder/postprocessing/DeleteOriginal.java @@ -0,0 +1,29 @@ +package ctbrec.recorder.postprocessing; + +import static ctbrec.io.IoUtils.*; + +import java.io.IOException; +import java.nio.file.Files; + +import ctbrec.Recording; + +public class DeleteOriginal extends AbstractPostProcessor { + + @Override + public String getName() { + return "delete original"; + } + + @Override + public void postprocess(Recording rec) throws IOException, InterruptedException { + if (rec.getAbsoluteFile().isFile()) { + Files.deleteIfExists(rec.getAbsoluteFile().toPath()); + deleteEmptyParents(rec.getAbsoluteFile().getParentFile()); + } else { + deleteDirectory(rec.getAbsoluteFile()); + deleteEmptyParents(rec.getAbsoluteFile()); + } + rec.setAbsoluteFile(rec.getPostProcessedFile()); + rec.getAssociatedFiles().remove(rec.getAbsoluteFile().getCanonicalPath()); + } +} diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Move.java b/common/src/main/java/ctbrec/recorder/postprocessing/Move.java new file mode 100644 index 00000000..498922d3 --- /dev/null +++ b/common/src/main/java/ctbrec/recorder/postprocessing/Move.java @@ -0,0 +1,57 @@ +package ctbrec.recorder.postprocessing; +import static ctbrec.io.IoUtils.*; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.io.Files; + +import ctbrec.Recording; + +public class Move extends AbstractPlaceholderAwarePostProcessor { + + private static final Logger LOG = LoggerFactory.getLogger(Rename.class); + public static final String PATH_TEMPLATE = "path.template"; + public static final String DEFAULT = "${modelSanitizedName}" + File.separatorChar + "${localDateTime}"; + + @Override + public String getName() { + return "move"; + } + + @Override + public void postprocess(Recording rec) throws IOException { + String pathTemplate = getConfig().getOrDefault(PATH_TEMPLATE, DEFAULT); + String path = fillInPlaceHolders(pathTemplate, rec); + File src = rec.getPostProcessedFile(); + File target = new File(path, src.getName()); + LOG.info("Moving {} to {}", src.getName(), target.getParentFile().getCanonicalPath()); + Files.createParentDirs(target); + Files.move(rec.getPostProcessedFile(), target); + rec.setPostProcessedFile(target); + if (Objects.equals(src, rec.getAbsoluteFile())) { + rec.setAbsoluteFile(target); + } + rec.getAssociatedFiles().remove(src.getCanonicalPath()); + rec.getAssociatedFiles().add(target.getCanonicalPath()); + + if (src.isFile()) { + deleteEmptyParents(src.getParentFile()); + } else { + deleteEmptyParents(src); + } + } + + @Override + public String toString() { + String s = getName(); + if (getConfig().containsKey(PATH_TEMPLATE)) { + s += " [" + getConfig().get(PATH_TEMPLATE) + ']'; + } + return s; + } +} diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Remuxer.java b/common/src/main/java/ctbrec/recorder/postprocessing/Remux.java similarity index 89% rename from common/src/main/java/ctbrec/recorder/postprocessing/Remuxer.java rename to common/src/main/java/ctbrec/recorder/postprocessing/Remux.java index 0aa5051a..cd7071bb 100644 --- a/common/src/main/java/ctbrec/recorder/postprocessing/Remuxer.java +++ b/common/src/main/java/ctbrec/recorder/postprocessing/Remux.java @@ -14,9 +14,9 @@ import ctbrec.Recording; import ctbrec.io.StreamRedirectThread; import ctbrec.recorder.download.ProcessExitedUncleanException; -public class Remuxer extends AbstractPostProcessor { +public class Remux extends AbstractPostProcessor { - private static final Logger LOG = LoggerFactory.getLogger(Remuxer.class); + private static final Logger LOG = LoggerFactory.getLogger(Remux.class); public static final String FFMPEG_ARGS = "ffmpeg.args"; public static final String FILE_EXT = "file.ext"; @@ -35,6 +35,7 @@ public class Remuxer extends AbstractPostProcessor { argsPlusFile[i++] = "-i"; argsPlusFile[i++] = rec.getPostProcessedFile().getAbsolutePath(); 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); @@ -42,7 +43,10 @@ public class Remuxer extends AbstractPostProcessor { Process ffmpeg = Runtime.getRuntime().exec(cmdline, new String[0], rec.getPostProcessedFile().getParentFile()); setupLogging(ffmpeg, rec); rec.setPostProcessedFile(remuxedFile); - rec.getAssociatedFiles().add(remuxedFile.getAbsolutePath()); + rec.setAbsoluteFile(remuxedFile); + Files.deleteIfExists(inputFile.toPath()); + rec.getAssociatedFiles().remove(inputFile.getCanonicalPath()); + rec.getAssociatedFiles().add(remuxedFile.getCanonicalPath()); } private void setupLogging(Process ffmpeg, Recording rec) throws IOException, InterruptedException { diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java b/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java new file mode 100644 index 00000000..a785be23 --- /dev/null +++ b/common/src/main/java/ctbrec/recorder/postprocessing/Rename.java @@ -0,0 +1,48 @@ +package ctbrec.recorder.postprocessing; +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.io.Files; + +import ctbrec.Recording; + +public class Rename extends AbstractPlaceholderAwarePostProcessor { + + private static final Logger LOG = LoggerFactory.getLogger(Rename.class); + public static final String FILE_NAME_TEMPLATE = "filename.template"; + public static final String DEFAULT = "${modelSanitizedName}_${localDateTime}.${fileSuffix}"; + + @Override + public String getName() { + return "rename"; + } + + @Override + public void postprocess(Recording rec) throws IOException { + String filenameTemplate = getConfig().getOrDefault(FILE_NAME_TEMPLATE, DEFAULT); + String filename = fillInPlaceHolders(filenameTemplate, rec); + File src = rec.getPostProcessedFile(); + File target = new File(src.getParentFile(), filename); + LOG.info("Renaming {} to {}", src.getName(), target.getName()); + Files.move(rec.getPostProcessedFile(), target); + rec.setPostProcessedFile(target); + if (Objects.equals(src, rec.getAbsoluteFile())) { + rec.setAbsoluteFile(target); + } + rec.getAssociatedFiles().remove(src.getCanonicalPath()); + rec.getAssociatedFiles().add(target.getCanonicalPath()); + } + + @Override + public String toString() { + String s = getName(); + if (getConfig().containsKey(FILE_NAME_TEMPLATE)) { + s += " [" + getConfig().get(FILE_NAME_TEMPLATE) + ']'; + } + return s; + } +}