diff --git a/source/net/filebot/Cache.java b/source/net/filebot/Cache.java index 0dde3e4e..97affb12 100644 --- a/source/net/filebot/Cache.java +++ b/source/net/filebot/Cache.java @@ -19,6 +19,7 @@ public class Cache { public static final Duration ONE_DAY = Duration.ofDays(1); public static final Duration ONE_WEEK = Duration.ofDays(7); + public static final Duration ONE_MONTH = Duration.ofDays(30); public static Cache getCache(String name, CacheType type) { return CacheManager.getInstance().getCache(name, type); diff --git a/source/net/filebot/Resource.java b/source/net/filebot/Resource.java index 6e7fe158..a3f00ed9 100644 --- a/source/net/filebot/Resource.java +++ b/source/net/filebot/Resource.java @@ -1,8 +1,55 @@ package net.filebot; +import java.util.function.Function; + @FunctionalInterface public interface Resource { R get() throws Exception; + default Resource memoize() { + return new MemoizedResource(this); + } + + default Resource transform(Function function) { + return new TransformedResource(this, function); + } + +} + +class MemoizedResource implements Resource { + + private final Resource resource; + private R value; + + public MemoizedResource(Resource resource) { + this.resource = resource; + } + + @Override + public R get() throws Exception { + synchronized (resource) { + if (value == null) { + value = resource.get(); + } + return value; + } + } +} + +class TransformedResource implements Resource { + + private final Resource resource; + private final Function function; + + public TransformedResource(Resource resource, Function function) { + this.resource = resource; + this.function = function; + } + + @Override + public T get() throws Exception { + return function.apply(resource.get()); + } + } diff --git a/source/net/filebot/media/MediaDetection.java b/source/net/filebot/media/MediaDetection.java index c032929f..af2e1f52 100644 --- a/source/net/filebot/media/MediaDetection.java +++ b/source/net/filebot/media/MediaDetection.java @@ -22,7 +22,6 @@ import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -447,15 +446,15 @@ public class MediaDetection { } public static List matchSeriesByDirectMapping(Collection files) throws Exception { - Map seriesDirectMappings = releaseInfo.getSeriesDirectMappings(); + Map patterns = releaseInfo.getSeriesMappings(); List matches = new ArrayList(); for (File file : files) { - for (Entry it : seriesDirectMappings.entrySet()) { - if (it.getKey().matcher(getName(file)).find()) { - matches.add(it.getValue()); + patterns.forEach((pattern, seriesName) -> { + if (pattern.matcher(getName(file)).find()) { + matches.add(seriesName); } - } + }); } return matches; diff --git a/source/net/filebot/media/ReleaseInfo.java b/source/net/filebot/media/ReleaseInfo.java index d3996d2c..a822e559 100644 --- a/source/net/filebot/media/ReleaseInfo.java +++ b/source/net/filebot/media/ReleaseInfo.java @@ -337,8 +337,8 @@ public class ReleaseInfo { return compile("(? getSeriesMappings() throws Exception { + return seriesMappings.get(); } public TheTVDBSearchResult[] getTheTVDBIndex() throws Exception { @@ -349,24 +349,12 @@ public class ReleaseInfo { return anidbIndex.get(); } - public SubtitleSearchResult[] getOpenSubtitlesIndex() throws Exception { - return osdbIndex.get(); + public Movie[] getMovieList() throws Exception { + return movieIndex.get(); } - private Map seriesDirectMappings; - - public Map getSeriesDirectMappings() throws Exception { - if (seriesDirectMappings == null) { - Map mappings = new LinkedHashMap(); - for (String line : seriesDirectMappingsResource.get()) { - String[] tsv = line.split("\t", 2); - if (tsv.length == 2) { - mappings.put(compile("(?> seriesMappings = lines("url.series-mappings", Cache.ONE_WEEK).transform(lines -> { + Map map = new LinkedHashMap(lines.length); + stream(lines).map(s -> s.split("\t", 2)).filter(v -> v.length == 2).forEach(v -> { + Pattern pattern = compile("(? releaseGroup = patternResource("url.release-groups"); - protected final Resource queryBlacklist = patternResource("url.query-blacklist"); - protected final Resource excludeBlacklist = patternResource("url.exclude-blacklist"); - protected final Resource seriesDirectMappingsResource = patternResource("url.series-mappings"); + protected final Resource releaseGroup = lines("url.release-groups", Cache.ONE_WEEK); + protected final Resource queryBlacklist = lines("url.query-blacklist", Cache.ONE_WEEK); + protected final Resource excludeBlacklist = lines("url.exclude-blacklist", Cache.ONE_WEEK); - protected final Resource movieIndex = tsvResource("url.movie-list", this::parseMovie, Movie[]::new); - protected final Resource tvdbIndex = tsvResource("url.thetvdb-index", this::parseSeries, TheTVDBSearchResult[]::new); - protected final Resource anidbIndex = tsvResource("url.anidb-index", this::parseAnime, AnidbSearchResult[]::new); - protected final Resource osdbIndex = tsvResource("url.osdb-index", this::parseSubtitle, SubtitleSearchResult[]::new); + protected final Resource tvdbIndex = tsv("url.thetvdb-index", Cache.ONE_WEEK, this::parseSeries, TheTVDBSearchResult[]::new); + protected final Resource anidbIndex = tsv("url.anidb-index", Cache.ONE_WEEK, this::parseAnime, AnidbSearchResult[]::new); - private Movie parseMovie(String[] v) { - int imdbid = parseInt(v[0]); - int tmdbid = parseInt(v[1]); - int year = parseInt(v[2]); - String name = v[3]; - String[] aliasNames = copyOfRange(v, 4, v.length); - return new Movie(name, aliasNames, year, imdbid > 0 ? imdbid : -1, tmdbid > 0 ? tmdbid : -1, null); - } + protected final Resource movieIndex = tsv("url.movie-list", Cache.ONE_MONTH, this::parseMovie, Movie[]::new); + protected final Resource osdbIndex = tsv("url.osdb-index", Cache.ONE_MONTH, this::parseSubtitle, SubtitleSearchResult[]::new); private TheTVDBSearchResult parseSeries(String[] v) { int id = parseInt(v[0]); @@ -439,6 +425,15 @@ public class ReleaseInfo { return new AnidbSearchResult(aid, primaryTitle, aliasNames); } + private Movie parseMovie(String[] v) { + int imdbid = parseInt(v[0]); + int tmdbid = parseInt(v[1]); + int year = parseInt(v[2]); + String name = v[3]; + String[] aliasNames = copyOfRange(v, 4, v.length); + return new Movie(name, aliasNames, year, imdbid > 0 ? imdbid : -1, tmdbid > 0 ? tmdbid : -1, null); + } + private SubtitleSearchResult parseSubtitle(String[] v) { String kind = v[0]; int score = parseInt(v[1]); @@ -449,20 +444,20 @@ public class ReleaseInfo { return new SubtitleSearchResult(name, aliasNames, year, imdbId, -1, Locale.ENGLISH, SubtitleSearchResult.Kind.forName(kind), score); } - protected Resource patternResource(String name) { - return resource(name, Cache.ONE_WEEK, s -> { + protected Resource lines(String name, Duration expirationTime) { + return resource(name, expirationTime, s -> { return s.length() > 0 ? s : null; - }, String[]::new); + }, String[]::new).memoize(); } - protected Resource tsvResource(String name, Function parse, IntFunction generator) { - return resource(name, Cache.ONE_WEEK, s -> { + protected Resource tsv(String name, Duration expirationTime, Function parse, IntFunction generator) { + return resource(name, expirationTime, s -> { String[] v = s.split("\t"); return v.length > 0 ? parse.apply(v) : null; - }, generator); + }, generator).memoize(); } - protected Resource resource(String name, Duration expirationTime, Function parse, IntFunction generator) { + protected Resource resource(String name, Duration expirationTime, Function parse, IntFunction generator) { return () -> { Cache cache = Cache.getCache("data", CacheType.Persistent); byte[] bytes = cache.bytes(name, n -> new URL(getProperty(n))).expire(expirationTime).get();