Refactor CmdlineInterface with proper types for all parameters

This commit is contained in:
Reinhard Pointner 2016-11-28 20:17:17 +08:00
parent 9720f60f50
commit 7a91e60858
2 changed files with 92 additions and 113 deletions

View File

@ -78,7 +78,7 @@ public class ArgumentProcessor {
Set<File> files = new LinkedHashSet<File>(args.getFiles(true)); Set<File> files = new LinkedHashSet<File>(args.getFiles(true));
if (args.extract) { if (args.extract) {
files.addAll(cli.extract(files, args.getOutputPath(), args.getConflictAction(), null, true)); files.addAll(cli.extract(files, args.getOutputPath(), args.getConflictAction(), null, args.isStrict()));
} }
if (args.getSubtitles) { if (args.getSubtitles) {

View File

@ -2,10 +2,10 @@ package net.filebot.cli;
import static java.util.Arrays.*; import static java.util.Arrays.*;
import static java.util.Collections.*; import static java.util.Collections.*;
import static java.util.stream.Collectors.*;
import static net.filebot.Logging.*; import static net.filebot.Logging.*;
import static net.filebot.media.XattrMetaInfo.*; import static net.filebot.media.XattrMetaInfo.*;
import static net.filebot.util.FileUtilities.*; import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.StringUtilities.*;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@ -14,20 +14,20 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.StringWriter; import java.io.StringWriter;
import java.lang.reflect.Field;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Objects;
import java.util.Set; import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.script.Bindings; import javax.script.Bindings;
import javax.script.SimpleBindings; import javax.script.SimpleBindings;
@ -217,6 +217,21 @@ public abstract class ScriptShellBaseClass extends Script {
return null; return null;
} }
public String getMediaInfo(File file, String format) throws Exception {
ExpressionFormat formatter = new ExpressionFormat(format);
Object o = xattr.getMetaInfo(file);
File f = file.getCanonicalFile();
try {
return formatter.format(new MediaBindingBean(o, f));
} catch (SuppressedThrowables e) {
debug.warning(format("%s => %s", format, e.getMessage()));
}
return null;
}
public String detectSeriesName(Object files) throws Exception { public String detectSeriesName(Object files) throws Exception {
return detectSeriesName(files, false); return detectSeriesName(files, false);
} }
@ -325,21 +340,19 @@ public abstract class ScriptShellBaseClass extends Script {
return null; return null;
} }
private enum Option {
action, conflict, query, filter, format, db, order, lang, output, encoding, strict, forceExtractAll
}
public List<File> rename(Map<String, ?> parameters) throws Exception { public List<File> rename(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
Map<Option, Object> option = getDefaultOptions(parameters); RenameAction action = getRenameAction(parameters);
RenameAction action = getRenameFunction(option.get(Option.action)); ArgumentBean args = getArgumentBean(parameters);
boolean strict = DefaultTypeTransformation.castToBoolean(option.get(Option.strict));
try { try {
if (input.isEmpty() && !getInputFileMap(parameters).isEmpty()) { if (files.size() > 0) {
return getCLI().rename(getInputFileMap(parameters), action, asString(option.get(Option.conflict))); return getCLI().rename(files, args.getRenameAction(), args.getConflictAction(), args.getAbsoluteOutputFolder(), args.getExpressionFormat(), args.getDatasource(), args.getSearchQuery(), args.getSortOrder(), args.getExpressionFilter(), args.getLanguage().getLocale(), args.isStrict());
} else { } else {
return getCLI().rename(input, action, asString(option.get(Option.conflict)), asString(option.get(Option.output)), asString(option.get(Option.format)), asString(option.get(Option.db)), asString(option.get(Option.query)), asString(option.get(Option.order)), asString(option.get(Option.filter)), asString(option.get(Option.lang)), strict); Map<File, File> map = getInputFileMap(parameters);
if (map.size() > 0) {
return getCLI().rename(map, action, args.getConflictAction());
}
} }
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
@ -349,12 +362,11 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public List<File> getSubtitles(Map<String, ?> parameters) throws Exception { public List<File> getSubtitles(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
Map<Option, Object> option = getDefaultOptions(parameters); ArgumentBean args = getArgumentBean(parameters);
boolean strict = DefaultTypeTransformation.castToBoolean(option.get(Option.strict));
try { try {
return getCLI().getSubtitles(input, asString(option.get(Option.db)), asString(option.get(Option.query)), asString(option.get(Option.lang)), asString(option.get(Option.output)), asString(option.get(Option.encoding)), asString(option.get(Option.format)), strict); return getCLI().getSubtitles(files, args.getSearchQuery(), args.getLanguage(), args.getSubtitleOutputFormat(), args.getEncoding(), args.getSubtitleNamingFormat(), args.isStrict());
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -363,12 +375,11 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public List<File> getMissingSubtitles(Map<String, ?> parameters) throws Exception { public List<File> getMissingSubtitles(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
Map<Option, Object> option = getDefaultOptions(parameters); ArgumentBean args = getArgumentBean(parameters);
boolean strict = DefaultTypeTransformation.castToBoolean(option.get(Option.strict));
try { try {
return getCLI().getMissingSubtitles(input, asString(option.get(Option.db)), asString(option.get(Option.query)), asString(option.get(Option.lang)), asString(option.get(Option.output)), asString(option.get(Option.encoding)), asString(option.get(Option.format)), strict); return getCLI().getMissingSubtitles(files, args.getSearchQuery(), args.getLanguage(), args.getSubtitleOutputFormat(), args.getEncoding(), args.getSubtitleNamingFormat(), args.isStrict());
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -377,10 +388,10 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public boolean check(Map<String, ?> parameters) throws Exception { public boolean check(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
try { try {
return getCLI().check(input); return getCLI().check(files);
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -389,11 +400,11 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public File compute(Map<String, ?> parameters) throws Exception { public File compute(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
Map<Option, Object> option = getDefaultOptions(parameters); ArgumentBean args = getArgumentBean(parameters);
try { try {
return getCLI().compute(input, asString(option.get(Option.output)), asString(option.get(Option.encoding))); return getCLI().compute(files, args.getOutputPath(), args.getOutputHashType(), args.getEncoding());
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -402,13 +413,12 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public List<File> extract(Map<String, ?> parameters) throws Exception { public List<File> extract(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
Map<Option, Object> option = getDefaultOptions(parameters); FileFilter filter = getFileFilter(parameters);
FileFilter filter = (FileFilter) DefaultTypeTransformation.castToType(option.get(Option.filter), FileFilter.class); ArgumentBean args = getArgumentBean(parameters);
boolean forceExtractAll = DefaultTypeTransformation.castToBoolean(option.get(Option.forceExtractAll));
try { try {
return getCLI().extract(input, asString(option.get(Option.output)), asString(option.get(Option.conflict)), filter, forceExtractAll); return getCLI().extract(files, args.getOutputPath(), args.getConflictAction(), filter, args.isStrict());
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -417,10 +427,10 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public List<String> fetchEpisodeList(Map<String, ?> parameters) throws Exception { public List<String> fetchEpisodeList(Map<String, ?> parameters) throws Exception {
Map<Option, Object> option = getDefaultOptions(parameters); ArgumentBean args = getArgumentBean();
try { try {
return getCLI().fetchEpisodeList(asString(option.get(Option.query)), asString(option.get(Option.format)), asString(option.get(Option.db)), asString(option.get(Option.order)), asString(option.get(Option.filter)), asString(option.get(Option.lang))); return getCLI().fetchEpisodeList(args.getDatasource(), args.getSearchQuery(), args.getExpressionFormat(), args.getExpressionFilter(), args.getSortOrder(), args.getLanguage().getLocale());
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -429,14 +439,11 @@ public abstract class ScriptShellBaseClass extends Script {
} }
public Object getMediaInfo(Map<String, ?> parameters) throws Exception { public Object getMediaInfo(Map<String, ?> parameters) throws Exception {
List<File> input = getInputFileList(parameters); List<File> files = getInputFileList(parameters);
if (input == null || input.isEmpty()) { ArgumentBean args = getArgumentBean(parameters);
return null;
}
Map<Option, Object> option = getDefaultOptions(parameters);
try { try {
return getCLI().getMediaInfo(input, asString(option.get(Option.format)), asString(option.get(Option.filter))); return getCLI().getMediaInfo(files, args.getExpressionFileFilter(), args.getExpressionFormat());
} catch (Exception e) { } catch (Exception e) {
printException(e); printException(e);
} }
@ -444,89 +451,61 @@ public abstract class ScriptShellBaseClass extends Script {
return null; return null;
} }
public String getMediaInfo(File file, String format) throws Exception { private ArgumentBean getArgumentBean(Map<String, ?> parameters) throws Exception {
ExpressionFormat formatter = new ExpressionFormat(format); // clone default arguments
ArgumentBean args = new ArgumentBean(getArgumentBean().getArgumentArray());
Object o = xattr.getMetaInfo(file); // for compatibility reasons [forceExtractAll: true] and [strict: true] is the same as -non-strict
File f = file.getCanonicalFile(); Stream.of("forceExtractAll", "strict").map(parameters::remove).filter(Objects::nonNull).forEach(v -> {
args.nonStrict = !DefaultTypeTransformation.castToBoolean(v);
});
try { // override default values with given values
return formatter.format(new MediaBindingBean(o, f)); parameters.forEach((k, v) -> {
} catch (SuppressedThrowables e) { try {
debug.warning(format("%s => %s", format, e.getMessage())); Field field = args.getClass().getField(k);
} Object value = DefaultTypeTransformation.castToType(v, field.getType());
field.set(args, value);
} catch (Exception e) {
throw new IllegalArgumentException("Illegal parameter: " + k, e);
}
});
return null; return args;
} }
private List<File> getInputFileList(Map<String, ?> parameters) { private List<File> getInputFileList(Map<String, ?> parameters) {
Object file = parameters.get("file"); // check file parameter add consume File values as they are
if (file != null) { return consumeParameter(parameters, "file").map(f -> asFileList(f)).findFirst().orElseGet(() -> {
return asFileList(file); // check folder parameter and resolve children
} return consumeParameter(parameters, "folder").flatMap(f -> asFileList(f).stream()).flatMap(f -> getChildren(f, FILES, HUMAN_NAME_ORDER).stream()).collect(toList());
});
Object folder = parameters.get("folder");
if (folder != null) {
List<File> files = new ArrayList<File>();
for (File f : asFileList(folder)) {
files.addAll(getChildren(f, FILES, HUMAN_NAME_ORDER));
}
return files;
}
return emptyList();
} }
private Map<File, File> getInputFileMap(Map<String, ?> parameters) { private Map<File, File> getInputFileMap(Map<String, ?> parameters) {
Map<?, ?> map = (Map<?, ?>) parameters.get("map"); // convert keys and values to files
Map<File, File> files = new LinkedHashMap<File, File>(); Function<Object, File> mapping = f -> asFileList(f).iterator().next();
if (map != null) {
for (Entry<?, ?> it : map.entrySet()) { return consumeParameter(parameters, "map").map(Map.class::cast).collect(toMap(mapping, mapping, (a, b) -> a, LinkedHashMap::new));
List<File> key = asFileList(it.getKey());
List<File> value = asFileList(it.getValue());
if (key.size() == 1 && value.size() == 1) {
files.put(key.get(0), value.get(0));
} else {
throw new IllegalArgumentException("Illegal file mapping: " + it);
}
}
}
return files;
} }
private Map<Option, Object> getDefaultOptions(Map<String, ?> parameters) throws Exception { private RenameAction getRenameAction(Map<String, ?> parameters) {
Map<Option, Object> options = new EnumMap<Option, Object>(Option.class); return consumeParameter(parameters, "action").map(action -> {
return getRenameAction(action);
for (Entry<String, ?> it : parameters.entrySet()) { }).findFirst().orElse(getArgumentBean().getRenameAction()); // default to global rename action
try {
options.put(Option.valueOf(it.getKey()), it.getValue());
} catch (Exception e) {
debug.warning(e::toString);
}
}
ArgumentBean args = getArgumentBean();
Set<Option> complement = EnumSet.allOf(Option.class);
complement.removeAll(options.keySet());
for (Option missing : complement) {
switch (missing) {
case forceExtractAll:
options.put(missing, false);
break;
case strict:
options.put(missing, !args.nonStrict);
break;
default:
options.put(missing, args.getClass().getField(missing.name()).get(args));
break;
}
}
return options;
} }
public RenameAction getRenameFunction(final Object obj) { private FileFilter getFileFilter(Map<String, ?> parameters) {
return consumeParameter(parameters, "filter").map(filter -> {
return (FileFilter) DefaultTypeTransformation.castToType(filter, FileFilter.class);
}).findFirst().orElse(null);
}
private Stream<?> consumeParameter(Map<String, ?> parameters, String... names) {
return Stream.of(names).map(parameters::remove).filter(Objects::nonNull);
}
public RenameAction getRenameAction(Object obj) {
if (obj instanceof RenameAction) { if (obj instanceof RenameAction) {
return (RenameAction) obj; return (RenameAction) obj;
} }