* improved fault-tolerance for fetch banner script

* santize Groovy stack trace
This commit is contained in:
Reinhard Pointner 2011-12-30 10:35:26 +00:00
parent 4390757fc3
commit a097daf079
5 changed files with 89 additions and 44 deletions

View File

@ -10,6 +10,7 @@ import java.io.File;
import java.security.AccessController; import java.security.AccessController;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import java.util.logging.Level;
import javax.script.Bindings; import javax.script.Bindings;
import javax.script.SimpleBindings; import javax.script.SimpleBindings;
@ -93,8 +94,8 @@ public class ArgumentProcessor {
CLILogger.finest("Done ヾ(@⌒ー⌒@)"); CLILogger.finest("Done ヾ(@⌒ー⌒@)");
return 0; return 0;
} catch (Exception e) { } catch (Throwable e) {
CLILogger.severe(String.format("%s: %s", getRootCause(e).getClass().getSimpleName(), getRootCauseMessage(e))); CLILogger.log(Level.SEVERE, String.format("%s: %s", getRootCause(e).getClass().getSimpleName(), getRootCauseMessage(e)), getRootCause(e));
CLILogger.finest("Failure (°_°)"); CLILogger.finest("Failure (°_°)");
return -1; return -1;
} }

View File

@ -4,6 +4,7 @@ package net.sourceforge.filebot.cli;
import static java.lang.System.*; import static java.lang.System.*;
import java.io.PrintStream;
import java.util.logging.Handler; import java.util.logging.Handler;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
@ -14,7 +15,7 @@ class CLILogging extends Handler {
public static final Logger CLILogger = createCommandlineLogger("net.sourceforge.filebot.cli"); public static final Logger CLILogger = createCommandlineLogger("net.sourceforge.filebot.cli");
private static Logger createCommandlineLogger(String name) { private static Logger createCommandlineLogger(String name) {
Logger log = Logger.getLogger(name); Logger log = Logger.getLogger(name);
log.setLevel(Level.ALL); log.setLevel(Level.ALL);
@ -28,13 +29,16 @@ class CLILogging extends Handler {
return log; return log;
} }
@Override @Override
public void publish(LogRecord record) { public void publish(LogRecord record) {
if (record.getLevel().intValue() <= getLevel().intValue()) if (record.getLevel().intValue() <= getLevel().intValue())
return; return;
// print messages to stdout // use either System.out or System.err depending on the severity of the error
PrintStream out = record.getLevel().intValue() < Level.WARNING.intValue() ? System.out : System.err;
// print messages
out.println(record.getMessage()); out.println(record.getMessage());
if (record.getThrown() != null) { if (record.getThrown() != null) {
record.getThrown().printStackTrace(out); record.getThrown().printStackTrace(out);
@ -44,13 +48,13 @@ class CLILogging extends Handler {
out.flush(); out.flush();
} }
@Override @Override
public void close() throws SecurityException { public void close() throws SecurityException {
} }
@Override @Override
public void flush() { public void flush() {
out.flush(); out.flush();

View File

@ -29,6 +29,7 @@ import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext; import javax.script.SimpleScriptContext;
import org.codehaus.groovy.jsr223.GroovyScriptEngineFactory; import org.codehaus.groovy.jsr223.GroovyScriptEngineFactory;
import org.codehaus.groovy.runtime.StackTraceUtils;
import net.sourceforge.filebot.MediaTypes; import net.sourceforge.filebot.MediaTypes;
import net.sourceforge.filebot.WebServices; import net.sourceforge.filebot.WebServices;
@ -92,7 +93,7 @@ class ScriptShell {
} }
public Object run(URL scriptLocation, Bindings bindings) throws Exception { public Object run(URL scriptLocation, Bindings bindings) throws Throwable {
if (scriptLocation.getProtocol().equals("file")) { if (scriptLocation.getProtocol().equals("file")) {
return run(new File(scriptLocation.toURI()), bindings); return run(new File(scriptLocation.toURI()), bindings);
} }
@ -109,27 +110,31 @@ class ScriptShell {
} }
public Object run(File scriptFile, Bindings bindings) throws Exception { public Object run(File scriptFile, Bindings bindings) throws Throwable {
String script = readAll(new InputStreamReader(new FileInputStream(scriptFile), "UTF-8")); String script = readAll(new InputStreamReader(new FileInputStream(scriptFile), "UTF-8"));
return evaluate(script, bindings); return evaluate(script, bindings);
} }
public Object evaluate(final String script, final Bindings bindings) throws Exception { public Object evaluate(final String script, final Bindings bindings) throws Throwable {
if (trustScript) {
return engine.eval(script, bindings);
}
try { try {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { if (trustScript) {
return engine.eval(script, bindings);
@Override }
public Object run() throws ScriptException {
return engine.eval(script, bindings); try {
} return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
}, getSandboxAccessControlContext());
} catch (PrivilegedActionException e) { @Override
throw e.getException(); public Object run() throws ScriptException {
return engine.eval(script, bindings);
}
}, getSandboxAccessControlContext());
} catch (PrivilegedActionException e) {
throw e.getException();
}
} catch (Throwable e) {
throw StackTraceUtils.deepSanitize(e); // make Groovy stack human-readable
} }
} }

View File

@ -19,6 +19,7 @@ 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.Random; import java.util.Random;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -638,15 +639,18 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
* *
* @see http://thetvdb.com/wiki/index.php/API:banners.xml * @see http://thetvdb.com/wiki/index.php/API:banners.xml
*/ */
public BannerDescriptor getBanner(TheTVDBSearchResult series, String bannerType, String bannerType2, Integer season, Locale locale, int index) throws Exception { public BannerDescriptor getBanner(TheTVDBSearchResult series, Map<?, ?> filterDescriptor) throws Exception {
EnumMap<BannerProperty, String> filter = new EnumMap<BannerProperty, String>(BannerProperty.class);
for (Entry<?, ?> it : filterDescriptor.entrySet()) {
if (it.getValue() != null) {
filter.put(BannerProperty.valueOf(it.getKey().toString()), it.getValue().toString());
}
}
// search for a banner matching the selector // search for a banner matching the selector
int n = 0;
for (BannerDescriptor it : getBannerList(series)) { for (BannerDescriptor it : getBannerList(series)) {
if ((bannerType == null || it.getBannerType().equalsIgnoreCase(bannerType)) && (bannerType2 == null || it.getBannerType2().equalsIgnoreCase(bannerType2)) && (season == null || it.getSeason().equals(season)) if (it.fields.entrySet().containsAll(filter.entrySet())) {
&& ((locale == null && it.getLocale().getLanguage().equals("en")) || it.getLocale().getLanguage().equals(locale.getLanguage()))) { return it;
if (index == n++) {
return it;
}
} }
} }
@ -736,12 +740,20 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
public URL getBannerMirrorUrl() throws MalformedURLException { public URL getBannerMirrorUrl() throws MalformedURLException {
return new URL(get(BannerProperty.BannerMirror)); try {
return new URL(get(BannerProperty.BannerMirror));
} catch (Exception e) {
return null;
}
} }
public URL getUrl() throws MalformedURLException { public URL getUrl() throws MalformedURLException {
return new URL(getBannerMirrorUrl(), get(BannerProperty.BannerPath)); try {
return new URL(getBannerMirrorUrl(), get(BannerProperty.BannerPath));
} catch (Exception e) {
return null;
}
} }
@ -750,8 +762,12 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
} }
public int getId() { public Integer getId() {
return Integer.parseInt(get(BannerProperty.id)); try {
return new Integer(get(BannerProperty.id));
} catch (Exception e) {
return null;
}
} }
@ -780,17 +796,29 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
public Locale getLocale() { public Locale getLocale() {
return new Locale(get(BannerProperty.Language)); try {
return new Locale(get(BannerProperty.Language));
} catch (Exception e) {
return null;
}
} }
public double getRating() { public Double getRating() {
return Double.parseDouble(get(BannerProperty.Rating)); try {
return new Double(get(BannerProperty.Rating));
} catch (Exception e) {
return null;
}
} }
public int getRatingCount() { public Integer getRatingCount() {
return Integer.parseInt(get(BannerProperty.RatingCount)); try {
return new Integer(get(BannerProperty.RatingCount));
} catch (Exception e) {
return null;
}
} }
@ -800,12 +828,20 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
public URL getThumbnailUrl() throws MalformedURLException { public URL getThumbnailUrl() throws MalformedURLException {
return new URL(getBannerMirrorUrl(), get(BannerProperty.ThumbnailPath)); try {
return new URL(getBannerMirrorUrl(), get(BannerProperty.ThumbnailPath));
} catch (Exception e) {
return null;
}
} }
public URL getVignetteUrl() throws MalformedURLException { public URL getVignetteUrl() throws MalformedURLException {
return new URL(getBannerMirrorUrl(), get(BannerProperty.VignettePath)); try {
return new URL(getBannerMirrorUrl(), get(BannerProperty.VignettePath));
} catch (Exception e) {
return null;
}
} }

View File

@ -1,8 +1,7 @@
// filebot -script "http://filebot.sf.net/scripts/artwork.tvdb.groovy" -trust-script /path/to/media/ // filebot -script "http://filebot.sf.net/scripts/artwork.tvdb.groovy" -trust-script /path/to/media/
// EXPERIMENTAL // HERE THERE BE DRAGONS // EXPERIMENTAL // HERE THERE BE DRAGONS
if (net.sourceforge.filebot.Settings.applicationRevisionNumber < 812) throw new Exception("Application revision too old") if (net.sourceforge.filebot.Settings.applicationRevisionNumber < 815) throw new Exception("Application revision too old")
/* /*
* Fetch series and season banners for all tv shows. Series name is auto-detected if possible or the folder name is used. * Fetch series and season banners for all tv shows. Series name is auto-detected if possible or the folder name is used.
@ -10,7 +9,7 @@ if (net.sourceforge.filebot.Settings.applicationRevisionNumber < 812) throw new
def fetchBanner(outputFile, series, bannerType, bannerType2 = null, season = null) { def fetchBanner(outputFile, series, bannerType, bannerType2 = null, season = null) {
// select and fetch banner // select and fetch banner
def banner = TheTVDB.getBanner(series, bannerType, bannerType2, season, Locale.ENGLISH, 0) def banner = ['en', null].findResult { TheTVDB.getBanner(series, [BannerType:bannerType, BannerType2:bannerType2, Season:season, Language:it]) }
if (banner == null) { if (banner == null) {
println "Banner not found: $outputFile / $bannerType:$bannerType2" println "Banner not found: $outputFile / $bannerType:$bannerType2"
return null return null