* ScriptShell rewrite nearing completion

This commit is contained in:
Reinhard Pointner 2014-04-17 19:52:23 +00:00
parent 396fb3508f
commit ad0e0e2802
5 changed files with 488 additions and 15 deletions

View File

@ -9,7 +9,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -177,6 +179,21 @@ public class History {
return sequences.hashCode();
}
public Map<File, File> getRenameMap() {
Map<File, File> map = new LinkedHashMap<File, File>();
for (History.Sequence seq : this.sequences()) {
for (History.Element elem : seq.elements()) {
File to = new File(elem.to());
if (!to.isAbsolute()) {
to = new File(elem.dir(), elem.to());
}
File from = new File(elem.dir(), elem.from());
map.put(from, to);
}
}
return map;
}
public static void exportHistory(History history, OutputStream output) {
try {
Marshaller marshaller = JAXBContext.newInstance(History.class).createMarshaller();

View File

@ -1,3 +1,3 @@
scriptBaseClass: net.sourceforge.filebot.cli.ScriptShellBaseClass
starImport: net.sourceforge.filebot, net.sourceforge.filebot.hash, net.sourceforge.filebot.media, net.sourceforge.filebot.mediainfo, net.sourceforge.filebot.similarity, net.sourceforge.filebot.subtitle, net.sourceforge.filebot.torrent, net.sourceforge.filebot.web, net.sourceforge.filebot.util, groovy.io, groovy.xml, groovy.json, org.jsoup, java.nio.file, java.nio.file.attribute, java.util.regex
starStaticImport: net.sourceforge.filebot.format.ExpressionFormatFunctions, net.sourceforge.filebot.WebServices, java.nio.file.Files
starStaticImport: net.sourceforge.filebot.WebServices, net.sourceforge.filebot.media.MediaDetection, net.sourceforge.filebot.format.ExpressionFormatFunctions

View File

@ -1,21 +1,42 @@
package net.sourceforge.filebot.cli;
import static java.util.Collections.*;
import static net.sourceforge.filebot.Settings.*;
import static net.sourceforge.filebot.cli.CLILogging.*;
import groovy.lang.Closure;
import groovy.lang.MissingPropertyException;
import groovy.lang.Script;
import groovy.xml.MarkupBuilder;
import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.StringWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
import javax.script.Bindings;
import javax.script.SimpleBindings;
import net.sourceforge.filebot.MediaTypes;
import net.sourceforge.filebot.HistorySpooler;
import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.WebServices;
import net.sourceforge.filebot.format.AssociativeScriptObject;
import net.sourceforge.filebot.media.MediaDetection;
import net.sourceforge.filebot.media.MetaAttributes;
import net.sourceforge.filebot.util.FileUtilities;
import net.sourceforge.filebot.web.Movie;
import com.sun.jna.Platform;
public abstract class ScriptShellBaseClass extends Script {
@ -107,7 +128,7 @@ public abstract class ScriptShellBaseClass extends Script {
// define global variable: _def
public Map<String, String> get_def() {
return getApplicationArguments().defines;
return unmodifiableMap(getApplicationArguments().defines);
}
// define global variable: _system
@ -120,13 +141,21 @@ public abstract class ScriptShellBaseClass extends Script {
return new AssociativeScriptObject(System.getenv());
}
// define global variable: _types
public MediaTypes get_types() {
return MediaTypes.getDefault();
// Complete or session rename history
public Map<File, File> getRenameLog() throws IOException {
return getRenameLog(false);
}
// define global variable: _log
public Logger get_log() {
public Map<File, File> getRenameLog(boolean complete) throws IOException {
if (complete) {
return HistorySpooler.getInstance().getCompleteHistory().getRenameMap();
} else {
return HistorySpooler.getInstance().getSessionHistory().getRenameMap();
}
}
// define global variable: log
public Logger getLog() {
return CLILogger;
}
@ -140,4 +169,95 @@ public abstract class ScriptShellBaseClass extends Script {
return null;
}
public String detectSeriesName(Object files) throws Exception {
List<String> names = MediaDetection.detectSeriesNames(FileUtilities.asFileList(files), true, false, Locale.ENGLISH);
return names.isEmpty() ? null : names.get(0);
}
public Movie detectMovie(File file, boolean strict) {
// 1. xattr
try {
return (Movie) new MetaAttributes(file).getObject();
} catch (Exception e) {
// ignore and move on
}
// 2. perfect filename match
try {
List<String> names = new ArrayList<String>();
for (File it : FileUtilities.listPathTail(file, 4, true)) {
names.add(it.getName());
}
return MediaDetection.matchMovieName(names, true, 0).get(0);
} catch (Exception e) {
// ignore and move on
}
// 3. run full-fledged movie detection
try {
return MediaDetection.detectMovie(file, WebServices.OpenSubtitles, WebServices.TheMovieDB, Locale.ENGLISH, strict).get(0);
} catch (Exception e) {
// ignore and fail
}
return null;
}
public int execute(Object... args) throws Exception {
List<String> cmd = new ArrayList<String>();
if (Platform.isWindows()) {
// normalize file separator for windows and run with cmd so any executable in PATH will just work
cmd.add("cmd");
cmd.add("/c");
} else if (args.length == 1) {
// make unix shell parse arguments
cmd.add("sh");
cmd.add("-c");
}
for (Object it : args) {
cmd.add(it.toString());
}
ProcessBuilder process = new ProcessBuilder(cmd).inheritIO();
return process.start().waitFor();
}
public String XML(Closure<?> buildClosure) {
StringWriter out = new StringWriter();
MarkupBuilder builder = new MarkupBuilder(out);
buildClosure.rehydrate(buildClosure.getDelegate(), builder, builder).call(); // call closure in MarkupBuilder context
return out.toString();
}
public void telnet(String host, int port, Closure<?> handler) throws IOException {
try (Socket socket = new Socket(host, port)) {
handler.call(new PrintStream(socket.getOutputStream(), true, "UTF-8"), new InputStreamReader(socket.getInputStream(), "UTF-8"));
}
}
private enum OptionName {
action, conflict, query, filter, format, db, order, lang, output, encoding, strict
}
private Map<OptionName, Object> withDefaultOptions(Map<String, ?> map) throws Exception {
Map<OptionName, Object> options = new EnumMap<OptionName, Object>(OptionName.class);
for (Entry<String, ?> it : map.entrySet()) {
options.put(OptionName.valueOf(it.getKey()), it.getValue());
}
ArgumentBean defaultValues = Settings.getApplicationArguments();
for (OptionName missing : EnumSet.complementOf(EnumSet.copyOf(options.keySet()))) {
if (missing == OptionName.strict) {
options.put(missing, !defaultValues.nonStrict);
} else {
Object value = defaultValues.getClass().getField(missing.name()).get(defaultValues);
options.put(missing, value);
}
}
return options;
}
}

View File

@ -1,5 +1,342 @@
package net.sourceforge.filebot.cli;
import static java.util.Arrays.*;
import static java.util.Collections.*;
import static net.sourceforge.filebot.MediaTypes.*;
import groovy.lang.Closure;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import net.sourceforge.filebot.MediaTypes;
import net.sourceforge.filebot.MetaAttributeView;
import net.sourceforge.filebot.media.MediaDetection;
import net.sourceforge.filebot.media.MetaAttributes;
import net.sourceforge.filebot.similarity.NameSimilarityMetric;
import net.sourceforge.filebot.similarity.Normalization;
import net.sourceforge.filebot.similarity.SimilarityMetric;
import net.sourceforge.filebot.util.FileUtilities;
import net.sourceforge.filebot.web.WebRequest;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
public class ScriptShellMethods {
public static File resolve(File self, Object name) {
return new File(self, name.toString());
}
public static File resolveSibling(File self, Object name) {
return new File(self.getParentFile(), name.toString());
}
public static List<File> listFiles(File self, Closure<?> closure) {
File[] files = self.listFiles();
if (files == null)
return emptyList();
return (List<File>) DefaultGroovyMethods.findAll(asList(files), closure);
}
public static boolean isVideo(File self) {
return VIDEO_FILES.accept(self);
}
public static boolean isAudio(File self) {
return AUDIO_FILES.accept(self);
}
public static boolean isSubtitle(File self) {
return SUBTITLE_FILES.accept(self);
}
public static boolean isVerification(File self) {
return VERIFICATION_FILES.accept(self);
}
public static boolean isArchive(File self) {
return ARCHIVE_FILES.accept(self);
}
public static boolean isDisk(File self) throws Exception {
// check disk folder
if (self.isDirectory() && MediaDetection.isDiskFolder(self))
return true;
// check disk image
if (self.isFile() && MediaTypes.getDefaultFilter("video/iso").accept(self) && MediaDetection.isVideoDiskFile(self))
return true;
return false;
}
public static File getDir(File self) {
return self.getParentFile();
}
public static boolean hasFile(File self, Closure<?> closure) {
File[] files = self.listFiles();
if (files == null)
return false;
return DefaultGroovyMethods.find(asList(files), closure) != null;
}
public static List<File> getFiles(File self) {
return getFiles(self, null);
}
public static List<File> getFiles(File self, Closure<?> closure) {
return getFiles(singletonList(self), closure);
}
public static List<File> getFiles(Collection<?> self) {
return getFiles(self, null);
}
public static List<File> getFiles(Collection<?> self, Closure<?> closure) {
final List<File> roots = FileUtilities.asFileList(self.toArray());
List<File> files = FileUtilities.listFiles(roots);
if (closure != null) {
files = (List<File>) DefaultGroovyMethods.findAll(files, closure);
}
return FileUtilities.sortByUniquePath(files);
}
public static List<File> getFolders(File self) {
return getFolders(self, null);
}
public static List<File> getFolders(File self, Closure<?> closure) {
return getFolders(singletonList(self), closure);
}
public static List<File> getFolders(Collection<?> self) {
return getFolders(self, null);
}
public static List<File> getFolders(Collection<?> self, Closure<?> closure) {
final List<File> roots = FileUtilities.asFileList(self.toArray());
List<File> folders = FileUtilities.listFolders(roots);
if (closure != null) {
folders = (List<File>) DefaultGroovyMethods.findAll(folders, closure);
}
return FileUtilities.sortByUniquePath(folders);
}
public static List<File> getMediaFolders(File self) throws IOException {
final List<File> mediaFolders = new ArrayList<File>();
Files.walkFileTree(self.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
File folder = dir.toFile();
if (FileUtilities.filter(asList(folder.listFiles()), VIDEO_FILES).size() > 0 || MediaDetection.isDiskFolder(folder)) {
mediaFolders.add(folder);
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
});
return FileUtilities.sortByUniquePath(mediaFolders);
}
public static String getNameWithoutExtension(File self) {
return FileUtilities.getNameWithoutExtension(self.getName());
}
public static String getNameWithoutExtension(String self) {
return FileUtilities.getNameWithoutExtension(self);
}
public static String getExtension(File self) {
return FileUtilities.getExtension(self);
}
public static String getExtension(String self) {
return FileUtilities.getExtension(self);
}
public static boolean hasExtension(File self, String... extensions) {
return FileUtilities.hasExtension(self, extensions);
}
public static boolean hasExtension(String self, String... extensions) {
return FileUtilities.hasExtension(self, extensions);
}
public static boolean isDerived(File self, File other) {
return FileUtilities.isDerived(self, other);
}
public static File validateFileName(File self) {
return FileUtilities.validateFileName(self);
}
public static String validateFileName(String self) {
return FileUtilities.validateFileName(self);
}
public static File validateFilePath(File self) {
return FileUtilities.validateFilePath(self);
}
public static File moveTo(File self, File destination) throws IOException {
return FileUtilities.moveRename(self, destination);
}
public static File copyAs(File self, File destination) throws IOException {
return FileUtilities.copyAs(self, destination);
}
public static File copyTo(File self, File destination) throws IOException {
return FileUtilities.copyAs(self, new File(destination, self.getName()));
}
public static File relativize(File self, File other) throws IOException {
return self.getCanonicalFile().toPath().relativize(other.getCanonicalFile().toPath()).toFile();
}
public static Map<File, List<File>> mapByFolder(Collection<?> files) {
return FileUtilities.mapByFolder(FileUtilities.asFileList(files));
}
public static Map<String, List<File>> mapByExtension(Collection<?> files) {
return FileUtilities.mapByExtension(FileUtilities.asFileList(files));
}
public static String normalizePunctuation(String self) {
return Normalization.normalizePunctuation(self);
}
// Web and File IO helpers
public static ByteBuffer fetch(URL self) throws IOException {
return WebRequest.fetch(self);
}
public static String getText(ByteBuffer self) {
return Charset.forName("UTF-8").decode(self.duplicate()).toString();
}
public static ByteBuffer post(URL self, Map<String, ?> parameters, Map<String, String> requestParameters) throws IOException {
return WebRequest.post(self, parameters, requestParameters);
}
public static ByteBuffer post(URL self, String text, Map<String, String> requestParameters) throws IOException {
return WebRequest.post(self, text.getBytes("UTF-8"), "text/plain", requestParameters);
}
public static File saveAs(ByteBuffer self, File file) throws IOException {
// resolve relative paths
file = file.getAbsoluteFile();
// make sure parent folders exist
file.getParentFile().mkdirs();
return FileUtilities.writeFile(self, file);
}
public static File saveAs(String self, File file) throws IOException {
return saveAs(Charset.forName("UTF-8").encode(self), file);
}
public static File saveAs(URL self, File file) throws IOException {
// resolve relative paths
file = file.getAbsoluteFile();
// make sure parent folders exist
file.getParentFile().mkdirs();
org.apache.commons.io.FileUtils.copyURLToFile(self, file);
return file;
}
public static String objectToJson(Object self) throws IOException {
return JsonWriter.objectToJson(self);
}
public static Object jsonToObject(String self) throws IOException {
return JsonReader.jsonToJava(self);
}
public static FolderWatchService watch(File self, final Closure<?> callback) throws IOException {
FolderWatchService watchService = new FolderWatchService(true) {
@Override
public void processCommitSet(File[] files, File dir) {
callback.call(asList(files));
}
};
// collect updates for 500 ms and then batch process
watchService.setCommitDelay(500);
watchService.setCommitPerFolder(true);
// start watching the given folder
watchService.watchFolder(self);
return watchService;
}
public static float getSimilarity(String self, String other) {
return new NameSimilarityMetric().getSimilarity(self, other);
}
public static Collection<?> getSimilarity(Collection<?> self, final Object prime, final Closure<String> toStringFunction) {
final SimilarityMetric metric = new NameSimilarityMetric();
List<Object> values = new ArrayList<Object>(self);
Collections.sort(values, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
String s1 = toStringFunction != null ? toStringFunction.call(o1) : o1.toString();
String s2 = toStringFunction != null ? toStringFunction.call(o2) : o2.toString();
return Float.compare(metric.getSimilarity(s2, prime), metric.getSimilarity(s1, prime));
}
});
return values;
}
public static MetaAttributeView getXattr(File self) {
try {
return new MetaAttributeView(self);
} catch (Exception e) {
return null;
}
}
public static Object getMetadata(File self) {
try {
return new MetaAttributes(self);
} catch (Exception e) {
return null;
}
}
}

View File

@ -158,14 +158,11 @@ public final class FileUtilities {
return text.toString();
}
public static void writeFile(ByteBuffer data, File destination) throws IOException {
FileChannel fileChannel = new FileOutputStream(destination).getChannel();
try {
fileChannel.write(data);
} finally {
fileChannel.close();
public static File writeFile(ByteBuffer data, File destination) throws IOException {
try (FileOutputStream stream = new FileOutputStream(destination); FileChannel channel = stream.getChannel()) {
channel.write(data);
}
return destination;
}
public static List<String[]> readCSV(InputStream source, String charsetName, String separatorPattern) {
@ -561,6 +558,8 @@ public final class FileUtilities {
files.add((File) it);
} else if (it instanceof Path) {
files.add(((Path) it).toFile());
} else if (it instanceof Collection<?>) {
files.addAll(asFileList(it)); // flatten object structure
}
}
return files;