Skip to content

Commit

Permalink
Fixed handling of quoted files names with spaces in them
Browse files Browse the repository at this point in the history
  • Loading branch information
KKDad committed Dec 31, 2017
1 parent 7dc815d commit cf610af
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 431 deletions.
622 changes: 250 additions & 372 deletions .idea/workspace.xml

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/main/java/org/westfield/ProcessingLoggingHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class ProcessingLoggingHandler extends Thread {
private final Logger logger;
private final InputStream inputStream;
private final List<String> filterList;
private final String prefix;

private StringBuilder output = new StringBuilder();

Expand All @@ -21,11 +22,12 @@ public class ProcessingLoggingHandler extends Thread {
* @param logger - Logger to log output to, optional. Log logging if not supplied
* @param filterList - List to filter output to the logger. If any regex matches, line is omitted
*/
public ProcessingLoggingHandler(InputStream inputStream, Logger logger, List<String> filterList)
public ProcessingLoggingHandler(String prefix, InputStream inputStream, Logger logger, List<String> filterList)
{
this.inputStream = inputStream;
this.logger = logger;
this.filterList = new ArrayList<>();
this.prefix = prefix;
if (filterList != null)
this.filterList.addAll(filterList);
}
Expand Down Expand Up @@ -53,7 +55,7 @@ private void logOutput(String line)
for (String filter : this.filterList)
if (line.contains(filter))
return;
logger.info(line);
logger.info("{}: {}", this.prefix, line);
}
}

Expand Down
18 changes: 14 additions & 4 deletions src/main/java/org/westfield/action/CommercialDetect.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class CommercialDetect extends Action {
private String comskipIni;
private String threads;
private Boolean hwassist;
private Boolean saveCutList;

@Override
public void describe()
Expand All @@ -37,6 +38,7 @@ public boolean configure(MediaToolConfig config) {
this.comskipIni = config.getCommercialDetect().get("configuration");
this.threads = config.getCommercialDetect().get("threads");
this.hwassist = Boolean.parseBoolean(config.getCommercialDetect().get("hwassist"));
this.saveCutList = Boolean.parseBoolean(config.getCommercialDetect().get("saveCutList"));

logger.debug("CommercialDetect is {}", this.enabled ? "enabled" : "Disabled");
return true;
Expand All @@ -48,6 +50,10 @@ public IMediaDetails process(IMediaDetails details)
if (!this.enabled)
return details;

// Reuse the preserved CutList if configured to do so
if (this.saveCutList && loadCutList(details))
return details;

boolean hasCommercials = detectCommercials(details);
if (hasCommercials)
loadCutList(details);
Expand All @@ -63,8 +69,8 @@ private boolean detectCommercials(IMediaDetails details)
try {
logger.info("Checking for Commercials...");
Process process = new ProcessBuilder(this.comskip, "--ini", this.comskipIni, "--threads", this.threads, this.hwassist ? "--hwassist" : "", "--zpcut", details.getMediaFile().getAbsolutePath()).start();
ProcessingLoggingHandler outputHandler = new ProcessingLoggingHandler(process.getInputStream(), logger, null);
ProcessingLoggingHandler errorHandler = new ProcessingLoggingHandler(process.getErrorStream(), logger, null);
ProcessingLoggingHandler outputHandler = new ProcessingLoggingHandler("STDOUT", process.getInputStream(), logger, null);
ProcessingLoggingHandler errorHandler = new ProcessingLoggingHandler("STDERR", process.getErrorStream(), logger, null);
outputHandler.start();
errorHandler.start();
int rc = process.waitFor();
Expand All @@ -78,26 +84,30 @@ private boolean detectCommercials(IMediaDetails details)
return false;
}

private void loadCutList(IMediaDetails details)
private boolean loadCutList(IMediaDetails details)
{
try {
File cutFile = new File(details.getMediaFile().getParent(), Files.getNameWithoutExtension(details.getMediaFile().getAbsolutePath()) + ".cut");
if (cutFile.exists()) {
List<String> jumpSegments = Files.asCharSource(cutFile, Charset.forName("UTF-8")).readLines();
details.getExtendedDetails().putIfAbsent("CutList", jumpSegments);
return true;
} else {
logger.warn("No CutList located after comskip exited.");
logger.warn("CutList not located.");
}
} catch (IOException ioe) {
logger.error(ioe.getMessage(), ioe);
}
return false;
}

@SuppressWarnings("squid:S899")
void cleanup(IMediaDetails details) {
List<String> tempExtensions = ImmutableList.of(".cut", ".txt", ".VPrj");

for (String ext : tempExtensions) {
if (this.saveCutList && ext.endsWith(".cut"))
continue;
File cutFile = new File(details.getMediaFile().getParent(), Files.getNameWithoutExtension(details.getMediaFile().getAbsolutePath()) + ext);
if (cutFile.exists())
cutFile.delete();
Expand Down
108 changes: 73 additions & 35 deletions src/main/java/org/westfield/action/RemoveCommercials.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.westfield.action;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -99,12 +103,11 @@ public IMediaDetails process(IMediaDetails details) {
return null;

boolean success = combineChapters(chapters, details.getMediaFile().getAbsolutePath());
if (success) {
if (success)
move(details);
cleanup();
}
cleanup();

return details;
return success ? details : null;
}


Expand Down Expand Up @@ -135,8 +138,10 @@ private void move(IMediaDetails details)

try {
File f = new File(finalFilename(details.getMediaFile().getAbsolutePath()));
logger.error("Renaming {} to {}", f.getAbsolutePath(), details.getMediaFile().getAbsolutePath());
logger.info("Moving {}", f.getAbsolutePath());
logger.info(" to {}", details.getMediaFile().getAbsolutePath());
Files.move(f, details.getMediaFile());
logger.info("Moved.");
} catch (IOException ioe) {
logger.error(ioe.getMessage());
}
Expand All @@ -150,16 +155,32 @@ private boolean combineChapters(List<Chapter> chapters, String fileName)
concat.append(chapterFilename(fileName, chapter.chapterNumber)).append("|");
concat.setLength(concat.length() - 1);

List<String> cmdArgs = new ArrayList<>();
cmdArgs.add(this.ffmpeg);
cmdArgs.add("-hide_banner");
cmdArgs.addAll(ImmutableList.of("-loglevel", "error"));
cmdArgs.add("-i");
cmdArgs.add(concat.toString());
cmdArgs.addAll(ImmutableList.of("-c", "copy"));
cmdArgs.add("-copy_unknown");
cmdArgs.add("-y");
cmdArgs.add(finalFilename(fileName));

try {
logger.info("Combining Chapters...");
Process process = new ProcessBuilder(this.ffmpeg, "-hide_banner", "-i", concat.toString(), "-c", "copy", "-y", finalFilename(fileName)).start();
ProcessingLoggingHandler outputHandler = new ProcessingLoggingHandler(process.getInputStream(), logger, getFilterList());
ProcessingLoggingHandler errorHandler = new ProcessingLoggingHandler(process.getErrorStream(), logger, getFilterList());
Process process = new ProcessBuilder(cmdArgs).start();
ProcessingLoggingHandler outputHandler = new ProcessingLoggingHandler("STDOUT", process.getInputStream(), logger, getFilterList());
ProcessingLoggingHandler errorHandler = new ProcessingLoggingHandler("STDERR", process.getErrorStream(), logger, getFilterList());
outputHandler.start();
errorHandler.start();
int rc = process.waitFor();
if (rc != 0)
logger.warn("Command exited with code: {}", rc);
if (rc != 0) {
Joiner joiner = Joiner.on(" ");
if (logger.isWarnEnabled()) {
logger.warn("Command exited with code: {}", rc);
logger.warn("{}", joiner.join(cmdArgs));
}
}
return rc == 0;

} catch (Exception ex) {
Expand All @@ -177,23 +198,37 @@ private boolean combineChapters(List<Chapter> chapters, String fileName)
*/
private int extractChapter(Chapter chapter, String fileName)
{
List<String> mpeg = getFilterList();
String cmd;
List<String> filterList = getFilterList();

List<String> cmdArgs = new ArrayList<>();
cmdArgs.add(this.ffmpeg);
cmdArgs.add("-hide_banner");
cmdArgs.addAll(ImmutableList.of("-loglevel", "error"));
cmdArgs.addAll(ImmutableList.of("-i", fileName));
cmdArgs.addAll(ImmutableList.of("-ss", DECIMAL_FORMAT.format(chapter.start)));
if (chapter.length > 0)
cmd = String.format("%s -hide_banner -loglevel error -i %s -ss %s -t %s %s -c copy -y %s", this.ffmpeg, fileName, DECIMAL_FORMAT.format(chapter.start), DECIMAL_FORMAT.format(chapter.length), generateMap(3), chapterFilename(fileName, chapter.chapterNumber));
else
cmd = String.format("%s -hide_banner -loglevel error -i %s -ss %s %s -c copy -y %s", this.ffmpeg, fileName, DECIMAL_FORMAT.format(chapter.start), generateMap(3), chapterFilename(fileName, chapter.chapterNumber));
logger.info("{}", cmd);
cmdArgs.addAll(ImmutableList.of("-t", DECIMAL_FORMAT.format(chapter.length)));
cmdArgs.addAll(generateMap(3));
cmdArgs.addAll(ImmutableList.of("-c", "copy"));
cmdArgs.add("-copy_unknown");
cmdArgs.addAll(ImmutableList.of("-y", chapterFilename(fileName, chapter.chapterNumber)));

try {
Process process = new ProcessBuilder(cmd.split("\\s+")).start();
ProcessingLoggingHandler outputHandler = new ProcessingLoggingHandler(process.getInputStream(), logger, mpeg);
ProcessingLoggingHandler errorHandler = new ProcessingLoggingHandler(process.getErrorStream(), logger, mpeg);
logger.info("Extracting Chapter {}, Length: {}", chapter.chapterNumber, chapter.length);
Process process = new ProcessBuilder(cmdArgs).start();
ProcessingLoggingHandler outputHandler = new ProcessingLoggingHandler("STDOUT", process.getInputStream(), logger, filterList);
ProcessingLoggingHandler errorHandler = new ProcessingLoggingHandler("STDERR", process.getErrorStream(), logger, filterList);
outputHandler.start();
errorHandler.start();

int rc = process.waitFor();
if (rc != 0)
logger.warn("Command exited with code: {}", rc);
if (rc != 0) {
Joiner joiner = Joiner.on(" ");
if (logger.isWarnEnabled()) {
logger.warn("Command exited with code: {}", rc);
logger.warn("{}", joiner.join(cmdArgs));
}
}
return rc;

} catch (Exception ex) {
Expand All @@ -207,12 +242,12 @@ private int extractChapter(Chapter chapter, String fileName)
*/
private static List<String> getFilterList()
{
List<String> mpeg = new ArrayList<>();
mpeg.add("buffer underflow");
mpeg.add("packet too large");
mpeg.add("Last message repeated");
mpeg.add("Invalid frame dimensions 0x0");
return mpeg;
List<String> filterList = new ArrayList<>();
filterList.add("buffer underflow");
filterList.add("packet too large");
filterList.add("Last message repeated");
filterList.add("Invalid frame dimensions 0x0");
return filterList;
}


Expand All @@ -221,23 +256,26 @@ private static List<String> getFilterList()
* @param numberOfStreams - Number of streams to generate. This should be 1 + number of Audio streams to copy.
* @return map parameter to pass ot the ffmpeg command line
*/
String generateMap(int numberOfStreams)
List<String> generateMap(int numberOfStreams)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numberOfStreams; i++)
sb.append("-map 0:").append(i).append(" ");
sb.setLength(sb.length() - 1);
return sb.toString();
List<String> mapList = new ArrayList<>();
for (int i = 0; i < numberOfStreams; i++) {
mapList.add("-map");
mapList.add(String.format("0:%d", i));
}
return mapList;
}

String chapterFilename(String fileName, int chapterNumber)
{
return Paths.get(this.tmpDir, String.format("%s-Chapter%s.%s", Files.getNameWithoutExtension(fileName), Integer.toString(chapterNumber), Files.getFileExtension(fileName))).toString();
String basename = Hashing.murmur3_32().newHasher().putString(fileName, Charsets.UTF_8).hash().toString();
return Paths.get(this.tmpDir, String.format("%s-Chapter%s.%s", basename, Integer.toString(chapterNumber), Files.getFileExtension(fileName))).toString();
}

String finalFilename(String fileName)
{
return Paths.get(this.tmpDir, String.format("%s-new.%s", Files.getNameWithoutExtension(fileName), Files.getFileExtension(fileName))).toString();
String basename = Hashing.murmur3_32().newHasher().putString(fileName, Charsets.UTF_8).hash().toString();
return Paths.get(this.tmpDir, String.format("%s-new.%s", basename, Files.getFileExtension(fileName))).toString();
}


Expand Down
16 changes: 9 additions & 7 deletions src/main/java/org/westfield/action/RenameMedia.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.westfield.action;

import com.google.common.io.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.westfield.parser.TokenParser;
Expand All @@ -8,6 +9,7 @@
import org.westfield.media.IMediaDetails;

import java.io.File;
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.text.ParseException;
Expand Down Expand Up @@ -76,11 +78,11 @@ public IMediaDetails process(IMediaDetails details) {
}
}

if (originalFile.renameTo(destinationFile)) {
logger.debug("Rename successful");
details.setMediaFile(destinationFile);
} else {
logger.debug("Rename failed");
try {
Files.move(originalFile, destinationFile);
logger.info("Moved.");
} catch (IOException ioe) {
logger.error(ioe.getMessage());
}
return details;
}
Expand All @@ -106,8 +108,8 @@ File generateDestinationFilename(IMediaDetails details, String formatString)
File destinationFile = Paths.get(this.destination, destFileName.toString()).toFile();
if (logger.isDebugEnabled()) {
logger.debug("----------------------------------");
logger.debug("Old Name: {}", details.getMediaFile());
logger.debug("New Name: {}", destinationFile);
logger.info("Moving {}", details.getMediaFile());
logger.info(" to {}", destinationFile);
}
return destinationFile;
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/MediaTool.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ actions:
- org.westfield.action.ProcessDelay
- org.westfield.action.BackupOriginal
- org.westfield.action.ShowLookup
#- org.westfield.action.RenameMedia
- org.westfield.action.InfoCreator
- org.westfield.action.CommercialDetect
- org.westfield.action.RemoveCommercials
#- org.westfield.action.Transcode
- org.westfield.action.Transcode
- org.westfield.action.RenameMedia

processDelay:
enabled: true
Expand Down Expand Up @@ -44,6 +44,7 @@ commercialDetect:
configuration: /data/git/comskip.ini
threads: 6
hwassist: true
saveCutList: true

removeCommercials:
enabled: true
Expand All @@ -52,7 +53,6 @@ removeCommercials:
transcode:
enabled: true


lookupHints:
- show: Border Security
id: 261999
Expand Down
20 changes: 12 additions & 8 deletions src/test/java/org.westfield/action/RemoveCommercialsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void generateDestinationChapterNameTest()
String result = subject.chapterFilename("foo.bar", 3);

// The file will be in a temporary directory and will end with
Assert.assertTrue(result.endsWith("foo-Chapter3.bar"));
Assert.assertTrue(result.endsWith("7fa0c9f6-Chapter3.bar"));
}

@Test
Expand All @@ -127,20 +127,24 @@ public void generateFinalNameTest()
String result = subject.finalFilename("foo.bar");

// The file will be in a temporary directory and will end with
Assert.assertTrue(result.endsWith("foo-new.bar"));
Assert.assertTrue(result.endsWith("7fa0c9f6-new.bar"));
}

@Test
public void generateMapTest()
{
List<String> expected2 = ImmutableList.of("-map", "0:0", "-map", "0:1");
List<String> expected3 = ImmutableList.of("-map", "0:0", "-map", "0:1", "-map", "0:2");
List<String> expected4 = ImmutableList.of("-map", "0:0", "-map", "0:1", "-map", "0:2", "-map", "0:3");

RemoveCommercials subject = getSubject();
String rc2 = subject.generateMap(2);
String rc3 = subject.generateMap(3);
String rc4 = subject.generateMap(4);
List<String> actual2 = subject.generateMap(2);
List<String> actual3 = subject.generateMap(3);
List<String> actual4 = subject.generateMap(4);

Assert.assertEquals("-map 0:0 -map 0:1", rc2);
Assert.assertEquals("-map 0:0 -map 0:1 -map 0:2", rc3);
Assert.assertEquals("-map 0:0 -map 0:1 -map 0:2 -map 0:3", rc4);
Assert.assertEquals(expected2, actual2);
Assert.assertEquals(expected3, actual3);
Assert.assertEquals(expected4, actual4);
}

@Test
Expand Down

0 comments on commit cf610af

Please sign in to comment.