mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-24 08:48:51 -05:00
Refactor
This commit is contained in:
parent
be5e65a844
commit
1ae3f5d2b8
@ -24,16 +24,16 @@ public class Cache {
|
||||
return CacheManager.getInstance().getCache(name, type);
|
||||
}
|
||||
|
||||
public CachedResource2<String, String> text(String key, Transform<String, URL> resource) {
|
||||
return new CachedResource2<String, String>(key, resource, fetchIfModified(), getText(UTF_8), String.class::cast, ONE_DAY, this);
|
||||
public <T> CachedResource2<T, String> text(T key, Transform<T, URL> resource) {
|
||||
return new CachedResource2<T, String>(key, resource, fetchIfModified(), getText(UTF_8), String.class::cast, ONE_DAY, this);
|
||||
}
|
||||
|
||||
public CachedResource2<String, Document> xml(String key, Transform<String, URL> resource) {
|
||||
return new CachedResource2<String, Document>(key, resource, fetchIfModified(), validateXml(getText(UTF_8)), getXml(String.class::cast), ONE_DAY, this);
|
||||
public <T> CachedResource2<T, Document> xml(T key, Transform<T, URL> resource) {
|
||||
return new CachedResource2<T, Document>(key, resource, fetchIfModified(), validateXml(getText(UTF_8)), getXml(String.class::cast), ONE_DAY, this);
|
||||
}
|
||||
|
||||
public CachedResource2<String, Object> json(String key, Transform<String, URL> resource) {
|
||||
return new CachedResource2<String, Object>(key, resource, fetchIfModified(), validateJson(getText(UTF_8)), getJson(String.class::cast), ONE_DAY, this);
|
||||
public <T> CachedResource2<T, Object> json(T key, Transform<T, URL> resource) {
|
||||
return new CachedResource2<T, Object>(key, resource, fetchIfModified(), validateJson(getText(UTF_8)), getJson(String.class::cast), ONE_DAY, this);
|
||||
}
|
||||
|
||||
private final net.sf.ehcache.Cache cache;
|
||||
|
@ -112,21 +112,11 @@ public class CachedResource2<K, R> {
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Fetch {
|
||||
ByteBuffer fetch(URL url, long lastModified) throws Exception;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Transform<T, R> {
|
||||
R transform(T object) throws Exception;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Permit {
|
||||
void acquire(URL resource) throws Exception;
|
||||
}
|
||||
|
||||
public static Transform<ByteBuffer, String> getText(Charset charset) {
|
||||
return (data) -> charset.decode(data).toString();
|
||||
}
|
||||
@ -159,41 +149,54 @@ public class CachedResource2<K, R> {
|
||||
};
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Fetch {
|
||||
ByteBuffer fetch(URL url, long lastModified) throws Exception;
|
||||
}
|
||||
|
||||
public static Fetch fetchIfModified() {
|
||||
return (url, lastModified) -> {
|
||||
try {
|
||||
debug.fine(format("Fetch %s (If-Modified-Since: %tc)", url, lastModified));
|
||||
debug.fine(WebRequest.log(url, lastModified, null));
|
||||
return WebRequest.fetchIfModified(url, lastModified);
|
||||
} catch (FileNotFoundException e) {
|
||||
debug.warning(format("Resource not found: %s => %s", url, e));
|
||||
return ByteBuffer.allocate(0);
|
||||
return fileNotFound(url, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Fetch fetchIfNoneMatch(Cache etagStorage) {
|
||||
return (url, lastModified) -> {
|
||||
// record ETag response header
|
||||
Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
|
||||
|
||||
String etagKey = url.toString();
|
||||
Object etagValue = etagStorage.get(etagKey);
|
||||
|
||||
try {
|
||||
debug.fine(format("Fetch %s (If-None-Match: %s, If-Modified-Since: %tc)", url, etagValue, lastModified));
|
||||
debug.fine(WebRequest.log(url, lastModified, etagValue));
|
||||
return WebRequest.fetch(url, lastModified, etagValue, null, responseHeaders);
|
||||
} catch (FileNotFoundException e) {
|
||||
debug.warning(format("Resource not found: %s => %s", url, e));
|
||||
return ByteBuffer.allocate(0);
|
||||
return fileNotFound(url, e);
|
||||
} finally {
|
||||
List<String> value = responseHeaders.get("ETag");
|
||||
if (value != null && value.size() > 0 && !value.contains(etagValue)) {
|
||||
debug.finest(format("ETag %s", value));
|
||||
etagStorage.put(etagKey, value.get(0));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ByteBuffer fileNotFound(URL url, FileNotFoundException e) {
|
||||
debug.warning(format("Resource not found: %s => %s", url, e.getMessage()));
|
||||
return ByteBuffer.allocate(0);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Permit {
|
||||
void acquire(URL resource) throws Exception;
|
||||
}
|
||||
|
||||
public static Fetch withPermit(Fetch fetch, Permit permit) {
|
||||
return (url, lastModified) -> {
|
||||
permit.acquire(url);
|
||||
|
@ -52,7 +52,7 @@ public final class Settings {
|
||||
try {
|
||||
return bundle.getString("apikey.appstore." + name);
|
||||
} catch (MissingResourceException e) {
|
||||
// ignore, fall back to default
|
||||
// use default value
|
||||
}
|
||||
}
|
||||
return bundle.getString("apikey." + name);
|
||||
|
@ -7,25 +7,24 @@ import static net.filebot.util.FileUtilities.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import net.filebot.Cache;
|
||||
import net.filebot.CacheType;
|
||||
import net.filebot.MediaTypes;
|
||||
import net.filebot.StandardRenameAction;
|
||||
import net.filebot.WebServices;
|
||||
import net.filebot.cli.ScriptShell.ScriptProvider;
|
||||
import net.filebot.web.CachedResource;
|
||||
|
||||
public class ArgumentProcessor {
|
||||
|
||||
@ -91,16 +90,16 @@ public class ArgumentProcessor {
|
||||
DefaultScriptProvider scriptProvider = new DefaultScriptProvider();
|
||||
URI script = scriptProvider.getScriptLocation(args.script);
|
||||
|
||||
if (!scriptProvider.isInlineScheme(script.getScheme())) {
|
||||
if (scriptProvider.getResourceTemplate(script.getScheme()) != null) {
|
||||
if (!scriptProvider.isInline(script)) {
|
||||
if (scriptProvider.resolveTemplate(script) != null) {
|
||||
scriptProvider.setBaseScheme(new URI(script.getScheme(), "%s", null));
|
||||
} else if ("file".equals(script.getScheme())) {
|
||||
File base = new File(script).getParentFile();
|
||||
File template = new File(base, "%s.groovy");
|
||||
} else if (scriptProvider.isFile(script)) {
|
||||
File parent = new File(script).getParentFile();
|
||||
File template = new File(parent, "%s.groovy");
|
||||
scriptProvider.setBaseScheme(template.toURI());
|
||||
} else {
|
||||
File base = new File(script.getPath()).getParentFile();
|
||||
String template = normalizePathSeparators(new File(base, "%s.groovy").getPath());
|
||||
File parent = new File(script.getPath()).getParentFile();
|
||||
String template = normalizePathSeparators(new File(parent, "%s.groovy").getPath());
|
||||
scriptProvider.setBaseScheme(new URI(script.getScheme(), script.getHost(), template, script.getQuery(), script.getFragment()));
|
||||
}
|
||||
}
|
||||
@ -129,78 +128,87 @@ public class ArgumentProcessor {
|
||||
|
||||
public static class DefaultScriptProvider implements ScriptProvider {
|
||||
|
||||
public static final String SCHEME_REMOTE_STABLE = "fn";
|
||||
public static final String SCHEME_REMOTE_DEVEL = "dev";
|
||||
public static final String SCHEME_INLINE_GROOVY = "g";
|
||||
public static final String SCHEME_LOCAL_FILE = "file";
|
||||
|
||||
public static final Pattern TEMPLATE_SCHEME = Pattern.compile("([a-z]{1,5}):(.+)");
|
||||
|
||||
public static final String NAME = "script";
|
||||
|
||||
private URI baseScheme;
|
||||
|
||||
public void setBaseScheme(URI baseScheme) {
|
||||
this.baseScheme = baseScheme;
|
||||
}
|
||||
|
||||
public String getResourceTemplate(String scheme) {
|
||||
public String resolveTemplate(URI uri) {
|
||||
try {
|
||||
return getApplicationProperty("script." + scheme);
|
||||
String template = getApplicationProperty(NAME + '.' + uri.getScheme());
|
||||
return String.format(template, uri.getSchemeSpecificPart());
|
||||
} catch (MissingResourceException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInlineScheme(String scheme) {
|
||||
return "g".equals(scheme);
|
||||
public boolean isInline(URI r) {
|
||||
return SCHEME_INLINE_GROOVY.equals(r.getScheme());
|
||||
}
|
||||
|
||||
public boolean isFile(URI r) {
|
||||
return SCHEME_LOCAL_FILE.equals(r.getScheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getScriptLocation(String input) throws Exception {
|
||||
try {
|
||||
return new URL(input).toURI();
|
||||
} catch (Exception e) {
|
||||
// g:println 'hello world'
|
||||
if (input.startsWith("g:")) {
|
||||
return new URI("g", input.substring(2), null);
|
||||
}
|
||||
// e.g. dev:amc
|
||||
Matcher template = TEMPLATE_SCHEME.matcher(input);
|
||||
if (template.matches()) {
|
||||
URI uri = new URI(template.group(1), template.group(2), null);
|
||||
|
||||
// fn:amc / dev:amc
|
||||
if (Pattern.matches("\\w+:.+", input)) {
|
||||
String scheme = input.substring(0, input.indexOf(':'));
|
||||
if (getResourceTemplate(scheme) != null) {
|
||||
return new URI(scheme, input.substring(scheme.length() + 1, input.length()), null);
|
||||
}
|
||||
// 1. fn:amc
|
||||
// 2. dev:sysinfo
|
||||
// 3. g:println 'hello world'
|
||||
switch (uri.getScheme()) {
|
||||
case SCHEME_REMOTE_STABLE:
|
||||
case SCHEME_REMOTE_DEVEL:
|
||||
case SCHEME_INLINE_GROOVY:
|
||||
return uri;
|
||||
default:
|
||||
return new URL(input).toURI();
|
||||
}
|
||||
|
||||
File file = new File(input);
|
||||
if (baseScheme != null && !file.isAbsolute()) {
|
||||
return new URI(baseScheme.getScheme(), String.format(baseScheme.getSchemeSpecificPart(), input), null);
|
||||
}
|
||||
|
||||
// X:/foo/bar.groovy
|
||||
if (!file.isFile()) {
|
||||
throw new FileNotFoundException(file.getPath());
|
||||
}
|
||||
return file.getAbsoluteFile().toURI();
|
||||
}
|
||||
|
||||
File file = new File(input);
|
||||
if (baseScheme != null && !file.isAbsolute()) {
|
||||
return new URI(baseScheme.getScheme(), String.format(baseScheme.getSchemeSpecificPart(), input), null);
|
||||
}
|
||||
|
||||
// e.g. /path/to/script.groovy
|
||||
if (!file.isFile()) {
|
||||
throw new FileNotFoundException(file.getPath());
|
||||
}
|
||||
return file.getCanonicalFile().toURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fetchScript(URI uri) throws IOException {
|
||||
if (uri.getScheme().equals("file")) {
|
||||
public String fetchScript(URI uri) throws Exception {
|
||||
if (isFile(uri)) {
|
||||
return readTextFile(new File(uri));
|
||||
}
|
||||
|
||||
if (uri.getScheme().equals("g")) {
|
||||
if (isInline(uri)) {
|
||||
return uri.getSchemeSpecificPart();
|
||||
}
|
||||
|
||||
// remote script
|
||||
String resolver = getResourceTemplate(uri.getScheme());
|
||||
String url = (resolver != null) ? String.format(resolver, uri.getSchemeSpecificPart()) : uri.toString();
|
||||
Cache cache = Cache.getCache(NAME, CacheType.Persistent);
|
||||
|
||||
// fetch remote script only if modified
|
||||
CachedResource<String> script = new CachedResource<String>(url, String.class, url.contains("/devel/") ? CachedResource.ONE_DAY : CachedResource.ONE_WEEK) {
|
||||
|
||||
@Override
|
||||
public String process(ByteBuffer data) {
|
||||
return Charset.forName("UTF-8").decode(data).toString();
|
||||
}
|
||||
};
|
||||
return script.get();
|
||||
return cache.text(uri.toString(), s -> {
|
||||
return new URL(resolveTemplate(uri));
|
||||
}).expire(SCHEME_REMOTE_DEVEL.equals(uri.getScheme()) ? Cache.ONE_DAY : Cache.ONE_WEEK).get();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,15 @@ import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
@ -309,6 +315,19 @@ public final class WebRequest {
|
||||
reader.parse(new InputSource(new StringReader(xml)));
|
||||
}
|
||||
|
||||
public static Supplier<String> log(URL url, long lastModified, Object etag) {
|
||||
return () -> {
|
||||
List<String> headers = new ArrayList<String>(2);
|
||||
if (lastModified > 0) {
|
||||
headers.add("If-Modified-Since: " + DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.ofInstant(Instant.ofEpochMilli(lastModified), ZoneOffset.UTC)));
|
||||
}
|
||||
if (etag != null) {
|
||||
headers.add("If-None-Match: " + etag);
|
||||
}
|
||||
return "Fetch resource: " + url + (headers.isEmpty() ? "" : " " + headers);
|
||||
};
|
||||
}
|
||||
|
||||
private WebRequest() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user