mirror of
https://github.com/mitb-archive/filebot
synced 2024-08-13 17:03:45 -04:00
* clean release info from any auto-detected series name word sequence
This commit is contained in:
parent
b93e85b9dd
commit
9cb97bf93a
@ -8,7 +8,7 @@ import static net.sourceforge.filebot.MediaTypes.*;
|
|||||||
import static net.sourceforge.filebot.WebServices.*;
|
import static net.sourceforge.filebot.WebServices.*;
|
||||||
import static net.sourceforge.filebot.cli.CLILogging.*;
|
import static net.sourceforge.filebot.cli.CLILogging.*;
|
||||||
import static net.sourceforge.filebot.hash.VerificationUtilities.*;
|
import static net.sourceforge.filebot.hash.VerificationUtilities.*;
|
||||||
import static net.sourceforge.filebot.similarity.SeriesNameMatcher.*;
|
import static net.sourceforge.filebot.mediainfo.ReleaseInfo.*;
|
||||||
import static net.sourceforge.filebot.subtitle.SubtitleUtilities.*;
|
import static net.sourceforge.filebot.subtitle.SubtitleUtilities.*;
|
||||||
import static net.sourceforge.tuned.FileUtilities.*;
|
import static net.sourceforge.tuned.FileUtilities.*;
|
||||||
|
|
||||||
@ -46,7 +46,6 @@ import net.sourceforge.filebot.format.MediaBindingBean;
|
|||||||
import net.sourceforge.filebot.hash.HashType;
|
import net.sourceforge.filebot.hash.HashType;
|
||||||
import net.sourceforge.filebot.hash.VerificationFileReader;
|
import net.sourceforge.filebot.hash.VerificationFileReader;
|
||||||
import net.sourceforge.filebot.hash.VerificationFileWriter;
|
import net.sourceforge.filebot.hash.VerificationFileWriter;
|
||||||
import net.sourceforge.filebot.mediainfo.ReleaseInfo;
|
|
||||||
import net.sourceforge.filebot.similarity.EpisodeMetrics;
|
import net.sourceforge.filebot.similarity.EpisodeMetrics;
|
||||||
import net.sourceforge.filebot.similarity.Match;
|
import net.sourceforge.filebot.similarity.Match;
|
||||||
import net.sourceforge.filebot.similarity.Matcher;
|
import net.sourceforge.filebot.similarity.Matcher;
|
||||||
@ -98,7 +97,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
|
|
||||||
Collection<String> cwsList = emptySet();
|
Collection<String> cwsList = emptySet();
|
||||||
if (max >= 5) {
|
if (max >= 5) {
|
||||||
cwsList = detectSeriesName(mediaFiles);
|
cwsList = detectSeriesNames(mediaFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesNameMatcher nameMatcher = new SeriesNameMatcher();
|
SeriesNameMatcher nameMatcher = new SeriesNameMatcher();
|
||||||
@ -557,10 +556,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||||||
|
|
||||||
|
|
||||||
private Collection<String> detectQuery(Collection<File> mediaFiles, boolean strict) throws Exception {
|
private Collection<String> detectQuery(Collection<File> mediaFiles, boolean strict) throws Exception {
|
||||||
Collection<String> names = detectSeriesName(mediaFiles);
|
Collection<String> names = detectSeriesNames(mediaFiles);
|
||||||
|
|
||||||
// clean detected word sequence from unwanted data
|
|
||||||
names = new LinkedHashSet<String>(new ReleaseInfo().cleanRG(names));
|
|
||||||
|
|
||||||
if (names.isEmpty() || (strict && names.size() > 1)) {
|
if (names.isEmpty() || (strict && names.size() > 1)) {
|
||||||
throw new Exception("Unable to auto-select query: " + names);
|
throw new Exception("Unable to auto-select query: " + names);
|
||||||
|
@ -12,27 +12,40 @@ import java.io.IOException;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import net.sourceforge.filebot.similarity.SeriesNameMatcher;
|
||||||
import net.sourceforge.filebot.web.CachedResource;
|
import net.sourceforge.filebot.web.CachedResource;
|
||||||
|
|
||||||
|
|
||||||
public class ReleaseInfo {
|
public class ReleaseInfo {
|
||||||
|
|
||||||
|
public static Collection<String> detectSeriesNames(Collection<File> files) throws IOException {
|
||||||
|
SeriesNameMatcher matcher = new SeriesNameMatcher();
|
||||||
|
ReleaseInfo cleaner = new ReleaseInfo();
|
||||||
|
|
||||||
|
// match common word sequence and clean detected word sequence from unwanted elements
|
||||||
|
Collection<String> names = matcher.matchAll(files.toArray(new File[files.size()]));
|
||||||
|
return new LinkedHashSet<String>(cleaner.cleanRG(names));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getVideoSource(File file) {
|
public String getVideoSource(File file) {
|
||||||
// check parent and itself for group names
|
// check parent and itself for group names
|
||||||
return matchLast(getVideoSourcePattern(), file.getParent(), file.getName());
|
return matchLast(getVideoSourcePattern(), file.getParent(), file.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getReleaseGroup(File file) throws IOException {
|
public String getReleaseGroup(File file) throws IOException {
|
||||||
// check parent and itself for group names
|
// check parent and itself for group names
|
||||||
return matchLast(getReleaseGroupPattern(), file.getParent(), file.getName());
|
return matchLast(getReleaseGroupPattern(), file.getParent(), file.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected String matchLast(Pattern pattern, CharSequence... sequence) {
|
protected String matchLast(Pattern pattern, CharSequence... sequence) {
|
||||||
String lastMatch = null;
|
String lastMatch = null;
|
||||||
|
|
||||||
@ -49,27 +62,27 @@ public class ReleaseInfo {
|
|||||||
return lastMatch;
|
return lastMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<String> clean(Iterable<String> items) throws IOException {
|
public List<String> clean(Iterable<String> items) throws IOException {
|
||||||
return clean(items, getVideoSourcePattern(), getCodecPattern());
|
return clean(items, getVideoSourcePattern(), getCodecPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String clean(String item) throws IOException {
|
public String clean(String item) throws IOException {
|
||||||
return clean(item, getVideoSourcePattern(), getCodecPattern());
|
return clean(item, getVideoSourcePattern(), getCodecPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<String> cleanRG(Iterable<String> items) throws IOException {
|
public List<String> cleanRG(Iterable<String> items) throws IOException {
|
||||||
return clean(items, getReleaseGroupPattern(), getVideoSourcePattern(), getCodecPattern());
|
return clean(items, getReleaseGroupPattern(), getVideoSourcePattern(), getCodecPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String cleanRG(String item) throws IOException {
|
public String cleanRG(String item) throws IOException {
|
||||||
return clean(item, getReleaseGroupPattern(), getVideoSourcePattern(), getCodecPattern());
|
return clean(item, getReleaseGroupPattern(), getVideoSourcePattern(), getCodecPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<String> clean(Iterable<String> items, Pattern... blacklisted) {
|
public List<String> clean(Iterable<String> items, Pattern... blacklisted) {
|
||||||
List<String> cleanedItems = new ArrayList<String>();
|
List<String> cleanedItems = new ArrayList<String>();
|
||||||
for (String it : items) {
|
for (String it : items) {
|
||||||
@ -79,7 +92,7 @@ public class ReleaseInfo {
|
|||||||
return cleanedItems;
|
return cleanedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String clean(String item, Pattern... blacklisted) {
|
public String clean(String item, Pattern... blacklisted) {
|
||||||
for (Pattern it : blacklisted) {
|
for (Pattern it : blacklisted) {
|
||||||
item = it.matcher(item).replaceAll("");
|
item = it.matcher(item).replaceAll("");
|
||||||
@ -88,27 +101,27 @@ public class ReleaseInfo {
|
|||||||
return item.replaceAll("[\\p{Punct}\\p{Space}]+", " ").trim();
|
return item.replaceAll("[\\p{Punct}\\p{Space}]+", " ").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Pattern getCodecPattern() {
|
public Pattern getCodecPattern() {
|
||||||
// pattern matching any video source name
|
// pattern matching any video source name
|
||||||
String pattern = getBundle(getClass().getName()).getString("pattern.codec");
|
String pattern = getBundle(getClass().getName()).getString("pattern.codec");
|
||||||
return compile("(?<!\\p{Alnum})(" + pattern + ")(?!\\p{Alnum})", CASE_INSENSITIVE);
|
return compile("(?<!\\p{Alnum})(" + pattern + ")(?!\\p{Alnum})", CASE_INSENSITIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Pattern getVideoSourcePattern() {
|
public Pattern getVideoSourcePattern() {
|
||||||
// pattern matching any video source name
|
// pattern matching any video source name
|
||||||
String pattern = getBundle(getClass().getName()).getString("pattern.video.source");
|
String pattern = getBundle(getClass().getName()).getString("pattern.video.source");
|
||||||
return compile("(?<!\\p{Alnum})(" + pattern + ")(?!\\p{Alnum})", CASE_INSENSITIVE);
|
return compile("(?<!\\p{Alnum})(" + pattern + ")(?!\\p{Alnum})", CASE_INSENSITIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Pattern getReleaseGroupPattern() throws IOException {
|
public Pattern getReleaseGroupPattern() throws IOException {
|
||||||
// pattern matching any release group name enclosed in separators
|
// pattern matching any release group name enclosed in separators
|
||||||
return compile("(?<!\\p{Alnum})(" + join(releaseGroupResource.get(), "|") + ")(?!\\p{Alnum})", CASE_INSENSITIVE);
|
return compile("(?<!\\p{Alnum})(" + join(releaseGroupResource.get(), "|") + ")(?!\\p{Alnum})", CASE_INSENSITIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// fetch release group names online and try to update the data every other day
|
// fetch release group names online and try to update the data every other day
|
||||||
protected final CachedResource<String[]> releaseGroupResource = new CachedResource<String[]>(getBundle(getClass().getName()).getString("url.release-groups"), DAYS.toMillis(2)) {
|
protected final CachedResource<String[]> releaseGroupResource = new CachedResource<String[]>(getBundle(getClass().getName()).getString("url.release-groups"), DAYS.toMillis(2)) {
|
||||||
|
|
||||||
|
@ -15,9 +15,9 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -28,17 +28,12 @@ import net.sourceforge.tuned.FileUtilities;
|
|||||||
|
|
||||||
public class SeriesNameMatcher {
|
public class SeriesNameMatcher {
|
||||||
|
|
||||||
public static Collection<String> detectSeriesName(Collection<File> files) {
|
|
||||||
return new SeriesNameMatcher().matchAll(files.toArray(new File[files.size()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected final SeasonEpisodeMatcher seasonEpisodeMatcher = new SeasonEpisodeMatcher(new SeasonEpisodeFilter(30, 50, 1000));
|
protected final SeasonEpisodeMatcher seasonEpisodeMatcher = new SeasonEpisodeMatcher(new SeasonEpisodeFilter(30, 50, 1000));
|
||||||
protected final NameSimilarityMetric nameSimilarityMetric = new NameSimilarityMetric();
|
protected final NameSimilarityMetric nameSimilarityMetric = new NameSimilarityMetric();
|
||||||
|
|
||||||
protected final int commonWordSequenceMaxStartIndex = 3;
|
protected final int commonWordSequenceMaxStartIndex = 3;
|
||||||
|
|
||||||
|
|
||||||
public Collection<String> matchAll(File[] files) {
|
public Collection<String> matchAll(File[] files) {
|
||||||
SeriesNameCollection seriesNames = new SeriesNameCollection();
|
SeriesNameCollection seriesNames = new SeriesNameCollection();
|
||||||
|
|
||||||
@ -59,7 +54,7 @@ public class SeriesNameMatcher {
|
|||||||
return seriesNames;
|
return seriesNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Collection<String> matchAll(String[] names) {
|
public Collection<String> matchAll(String[] names) {
|
||||||
SeriesNameCollection seriesNames = new SeriesNameCollection();
|
SeriesNameCollection seriesNames = new SeriesNameCollection();
|
||||||
|
|
||||||
@ -79,7 +74,7 @@ public class SeriesNameMatcher {
|
|||||||
return seriesNames;
|
return seriesNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to match and verify all series names using known season episode patterns.
|
* Try to match and verify all series names using known season episode patterns.
|
||||||
*
|
*
|
||||||
@ -114,7 +109,7 @@ public class SeriesNameMatcher {
|
|||||||
return thresholdCollection;
|
return thresholdCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to match all common word sequences in the given list.
|
* Try to match all common word sequences in the given list.
|
||||||
*
|
*
|
||||||
@ -144,7 +139,7 @@ public class SeriesNameMatcher {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to match a series name from the given episode name using known season episode
|
* Try to match a series name from the given episode name using known season episode
|
||||||
* patterns.
|
* patterns.
|
||||||
@ -164,7 +159,7 @@ public class SeriesNameMatcher {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to match a series name from the first common word sequence.
|
* Try to match a series name from the first common word sequence.
|
||||||
*
|
*
|
||||||
@ -202,7 +197,7 @@ public class SeriesNameMatcher {
|
|||||||
return join(common, " ");
|
return join(common, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected String normalize(String name) {
|
protected String normalize(String name) {
|
||||||
// remove group names and checksums, any [...] or (...)
|
// remove group names and checksums, any [...] or (...)
|
||||||
name = name.replaceAll("\\([^\\(]*\\)", "");
|
name = name.replaceAll("\\([^\\(]*\\)", "");
|
||||||
@ -215,7 +210,7 @@ public class SeriesNameMatcher {
|
|||||||
return name.trim();
|
return name.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected <T> T[] firstCommonSequence(T[] seq1, T[] seq2, int maxStartIndex, Comparator<T> equalsComparator) {
|
protected <T> T[] firstCommonSequence(T[] seq1, T[] seq2, int maxStartIndex, Comparator<T> equalsComparator) {
|
||||||
for (int i = 0; i < seq1.length && i <= maxStartIndex; i++) {
|
for (int i = 0; i < seq1.length && i <= maxStartIndex; i++) {
|
||||||
for (int j = 0; j < seq2.length && j <= maxStartIndex; j++) {
|
for (int j = 0; j < seq2.length && j <= maxStartIndex; j++) {
|
||||||
@ -241,7 +236,7 @@ public class SeriesNameMatcher {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Map<File, String[]> mapNamesByFolder(File... files) {
|
private Map<File, String[]> mapNamesByFolder(File... files) {
|
||||||
Map<File, List<File>> filesByFolder = new LinkedHashMap<File, List<File>>();
|
Map<File, List<File>> filesByFolder = new LinkedHashMap<File, List<File>>();
|
||||||
|
|
||||||
@ -268,7 +263,7 @@ public class SeriesNameMatcher {
|
|||||||
return namesByFolder;
|
return namesByFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected String[] names(Collection<File> files) {
|
protected String[] names(Collection<File> files) {
|
||||||
String[] names = new String[files.size()];
|
String[] names = new String[files.size()];
|
||||||
|
|
||||||
@ -282,12 +277,12 @@ public class SeriesNameMatcher {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static class SeriesNameCollection extends AbstractCollection<String> {
|
protected static class SeriesNameCollection extends AbstractCollection<String> {
|
||||||
|
|
||||||
private final Map<String, String> data = new LinkedHashMap<String, String>();
|
private final Map<String, String> data = new LinkedHashMap<String, String>();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(String value) {
|
public boolean add(String value) {
|
||||||
value = value.trim();
|
value = value.trim();
|
||||||
@ -308,12 +303,12 @@ public class SeriesNameMatcher {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected String key(Object value) {
|
protected String key(Object value) {
|
||||||
return value.toString().toLowerCase();
|
return value.toString().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected float firstCharacterCaseBalance(String s) {
|
protected float firstCharacterCaseBalance(String s) {
|
||||||
int upper = 0;
|
int upper = 0;
|
||||||
int lower = 0;
|
int lower = 0;
|
||||||
@ -333,19 +328,19 @@ public class SeriesNameMatcher {
|
|||||||
return (lower + (upper * 1.01f)) / Math.abs(lower - upper);
|
return (lower + (upper * 1.01f)) / Math.abs(lower - upper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object value) {
|
public boolean contains(Object value) {
|
||||||
return data.containsKey(key(value));
|
return data.containsKey(key(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<String> iterator() {
|
public Iterator<String> iterator() {
|
||||||
return data.values().iterator();
|
return data.values().iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return data.size();
|
return data.size();
|
||||||
@ -353,7 +348,7 @@ public class SeriesNameMatcher {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static class ThresholdCollection<E> extends AbstractCollection<E> {
|
protected static class ThresholdCollection<E> extends AbstractCollection<E> {
|
||||||
|
|
||||||
private final Collection<E> heaven;
|
private final Collection<E> heaven;
|
||||||
@ -361,14 +356,14 @@ public class SeriesNameMatcher {
|
|||||||
|
|
||||||
private final int threshold;
|
private final int threshold;
|
||||||
|
|
||||||
|
|
||||||
public ThresholdCollection(int threshold, Comparator<E> equalityComparator) {
|
public ThresholdCollection(int threshold, Comparator<E> equalityComparator) {
|
||||||
this.heaven = new ArrayList<E>();
|
this.heaven = new ArrayList<E>();
|
||||||
this.limbo = new TreeMap<E, Collection<E>>(equalityComparator);
|
this.limbo = new TreeMap<E, Collection<E>>(equalityComparator);
|
||||||
this.threshold = threshold;
|
this.threshold = threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(E value) {
|
public boolean add(E value) {
|
||||||
Collection<E> buffer = limbo.get(value);
|
Collection<E> buffer = limbo.get(value);
|
||||||
@ -400,18 +395,18 @@ public class SeriesNameMatcher {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public boolean addDirect(E element) {
|
public boolean addDirect(E element) {
|
||||||
return heaven.add(element);
|
return heaven.add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return heaven.iterator();
|
return heaven.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return heaven.size();
|
return heaven.size();
|
||||||
|
@ -4,7 +4,7 @@ package net.sourceforge.filebot.ui.rename;
|
|||||||
|
|
||||||
import static java.util.Collections.*;
|
import static java.util.Collections.*;
|
||||||
import static net.sourceforge.filebot.MediaTypes.*;
|
import static net.sourceforge.filebot.MediaTypes.*;
|
||||||
import static net.sourceforge.filebot.similarity.SeriesNameMatcher.*;
|
import static net.sourceforge.filebot.mediainfo.ReleaseInfo.*;
|
||||||
import static net.sourceforge.filebot.web.EpisodeUtilities.*;
|
import static net.sourceforge.filebot.web.EpisodeUtilities.*;
|
||||||
import static net.sourceforge.tuned.FileUtilities.*;
|
import static net.sourceforge.tuned.FileUtilities.*;
|
||||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||||
@ -51,12 +51,12 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
|
|
||||||
private final EpisodeListProvider provider;
|
private final EpisodeListProvider provider;
|
||||||
|
|
||||||
|
|
||||||
public EpisodeListMatcher(EpisodeListProvider provider) {
|
public EpisodeListMatcher(EpisodeListProvider provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected SearchResult selectSearchResult(final String query, final List<SearchResult> searchResults, final Component parent) throws Exception {
|
protected SearchResult selectSearchResult(final String query, final List<SearchResult> searchResults, final Component parent) throws Exception {
|
||||||
if (searchResults.size() == 1) {
|
if (searchResults.size() == 1) {
|
||||||
return searchResults.get(0);
|
return searchResults.get(0);
|
||||||
@ -111,13 +111,13 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
return showSelectDialog.get();
|
return showSelectDialog.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String normalizeName(String value) {
|
private String normalizeName(String value) {
|
||||||
// remove trailing braces, e.g. Doctor Who (2005) -> doctor who
|
// remove trailing braces, e.g. Doctor Who (2005) -> doctor who
|
||||||
return removeTrailingBrackets(value).toLowerCase();
|
return removeTrailingBrackets(value).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected Set<Episode> fetchEpisodeSet(Collection<String> seriesNames, final Locale locale, final Component parent) throws Exception {
|
protected Set<Episode> fetchEpisodeSet(Collection<String> seriesNames, final Locale locale, final Component parent) throws Exception {
|
||||||
List<Callable<List<Episode>>> tasks = new ArrayList<Callable<List<Episode>>>();
|
List<Callable<List<Episode>>> tasks = new ArrayList<Callable<List<Episode>>>();
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Match<File, ?>> match(final List<File> files, final Locale locale, final boolean autodetection, final Component parent) throws Exception {
|
public List<Match<File, ?>> match(final List<File> files, final Locale locale, final boolean autodetection, final Component parent) throws Exception {
|
||||||
// focus on movie and subtitle files
|
// focus on movie and subtitle files
|
||||||
@ -173,7 +173,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
final Map<File, List<File>> filesByFolder = mapByFolder(mediaFiles);
|
final Map<File, List<File>> filesByFolder = mapByFolder(mediaFiles);
|
||||||
|
|
||||||
// do matching all at once
|
// do matching all at once
|
||||||
if (filesByFolder.keySet().size() <= 5 || detectSeriesName(mediaFiles).size() <= 5) {
|
if (filesByFolder.keySet().size() <= 5 || detectSeriesNames(mediaFiles).size() <= 5) {
|
||||||
return matchEpisodeSet(mediaFiles, locale, autodetection, parent);
|
return matchEpisodeSet(mediaFiles, locale, autodetection, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,13 +209,13 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<Match<File, ?>> matchEpisodeSet(final List<File> files, Locale locale, boolean autodetection, Component parent) throws Exception {
|
public List<Match<File, ?>> matchEpisodeSet(final List<File> files, Locale locale, boolean autodetection, Component parent) throws Exception {
|
||||||
Set<Episode> episodes = emptySet();
|
Set<Episode> episodes = emptySet();
|
||||||
|
|
||||||
// detect series name and fetch episode list
|
// detect series name and fetch episode list
|
||||||
if (autodetection) {
|
if (autodetection) {
|
||||||
Collection<String> names = detectSeriesName(files);
|
Collection<String> names = detectSeriesNames(files);
|
||||||
if (names.size() > 0) {
|
if (names.size() > 0) {
|
||||||
// only allow one fetch session at a time so later requests can make use of cached results
|
// only allow one fetch session at a time so later requests can make use of cached results
|
||||||
synchronized (provider) {
|
synchronized (provider) {
|
||||||
|
@ -4,7 +4,7 @@ package net.sourceforge.filebot.ui.subtitle;
|
|||||||
|
|
||||||
import static javax.swing.BorderFactory.*;
|
import static javax.swing.BorderFactory.*;
|
||||||
import static javax.swing.JOptionPane.*;
|
import static javax.swing.JOptionPane.*;
|
||||||
import static net.sourceforge.filebot.similarity.SeriesNameMatcher.*;
|
import static net.sourceforge.filebot.mediainfo.ReleaseInfo.*;
|
||||||
import static net.sourceforge.filebot.subtitle.SubtitleUtilities.*;
|
import static net.sourceforge.filebot.subtitle.SubtitleUtilities.*;
|
||||||
import static net.sourceforge.tuned.FileUtilities.*;
|
import static net.sourceforge.tuned.FileUtilities.*;
|
||||||
import static net.sourceforge.tuned.StringUtilities.*;
|
import static net.sourceforge.tuned.StringUtilities.*;
|
||||||
@ -27,8 +27,8 @@ import java.util.HashMap;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -87,7 +87,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
private ExecutorService queryService;
|
private ExecutorService queryService;
|
||||||
private ExecutorService downloadService;
|
private ExecutorService downloadService;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleAutoMatchDialog(Window owner) {
|
public SubtitleAutoMatchDialog(Window owner) {
|
||||||
super(owner, "Download Subtitles", ModalityType.DOCUMENT_MODAL);
|
super(owner, "Download Subtitles", ModalityType.DOCUMENT_MODAL);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
content.add(new JButton(finishAction), "tag cancel");
|
content.add(new JButton(finishAction), "tag cancel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected JPanel createServicePanel(Color color) {
|
protected JPanel createServicePanel(Color color) {
|
||||||
JPanel panel = new JPanel(new MigLayout("hidemode 3"));
|
JPanel panel = new JPanel(new MigLayout("hidemode 3"));
|
||||||
panel.setBorder(new RoundBorder());
|
panel.setBorder(new RoundBorder());
|
||||||
@ -112,7 +112,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected JTable createTable() {
|
protected JTable createTable() {
|
||||||
JTable table = new JTable(new SubtitleMappingTableModel());
|
JTable table = new JTable(new SubtitleMappingTableModel());
|
||||||
table.setDefaultRenderer(SubtitleMapping.class, new SubtitleMappingOptionRenderer());
|
table.setDefaultRenderer(SubtitleMapping.class, new SubtitleMappingOptionRenderer());
|
||||||
@ -148,22 +148,22 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setVideoFiles(File[] videoFiles) {
|
public void setVideoFiles(File[] videoFiles) {
|
||||||
subtitleMappingTable.setModel(new SubtitleMappingTableModel(videoFiles));
|
subtitleMappingTable.setModel(new SubtitleMappingTableModel(videoFiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addSubtitleService(VideoHashSubtitleService service) {
|
public void addSubtitleService(VideoHashSubtitleService service) {
|
||||||
addSubtitleService(new VideoHashSubtitleServiceBean(service), hashMatcherServicePanel);
|
addSubtitleService(new VideoHashSubtitleServiceBean(service), hashMatcherServicePanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addSubtitleService(SubtitleProvider service) {
|
public void addSubtitleService(SubtitleProvider service) {
|
||||||
addSubtitleService(new SubtitleProviderBean(service, this), nameMatcherServicePanel);
|
addSubtitleService(new SubtitleProviderBean(service, this), nameMatcherServicePanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void addSubtitleService(final SubtitleServiceBean service, final JPanel servicePanel) {
|
protected void addSubtitleService(final SubtitleServiceBean service, final JPanel servicePanel) {
|
||||||
final LinkButton component = new LinkButton(service.getName(), ResourceManager.getIcon("database"), service.getLink());
|
final LinkButton component = new LinkButton(service.getName(), ResourceManager.getIcon("database"), service.getLink());
|
||||||
component.setVisible(false);
|
component.setVisible(false);
|
||||||
@ -189,11 +189,11 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
servicePanel.add(component);
|
servicePanel.add(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remember last user input
|
// remember last user input
|
||||||
private List<String> userQuery = new ArrayList<String>();
|
private List<String> userQuery = new ArrayList<String>();
|
||||||
|
|
||||||
|
|
||||||
protected List<String> getUserQuery(String suggestion, String title, Component parent) throws Exception {
|
protected List<String> getUserQuery(String suggestion, String title, Component parent) throws Exception {
|
||||||
synchronized (userQuery) {
|
synchronized (userQuery) {
|
||||||
if (userQuery.isEmpty()) {
|
if (userQuery.isEmpty()) {
|
||||||
@ -203,7 +203,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void startQuery(String languageName) {
|
public void startQuery(String languageName) {
|
||||||
final SubtitleMappingTableModel mappingModel = (SubtitleMappingTableModel) subtitleMappingTable.getModel();
|
final SubtitleMappingTableModel mappingModel = (SubtitleMappingTableModel) subtitleMappingTable.getModel();
|
||||||
QueryTask queryTask = new QueryTask(services, mappingModel.getVideoFiles(), languageName, SubtitleAutoMatchDialog.this) {
|
QueryTask queryTask = new QueryTask(services, mappingModel.getVideoFiles(), languageName, SubtitleAutoMatchDialog.this) {
|
||||||
@ -232,7 +232,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
queryService.submit(queryTask);
|
queryService.submit(queryTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Boolean showConfirmReplaceDialog(List<?> files) {
|
private Boolean showConfirmReplaceDialog(List<?> files) {
|
||||||
JList existingFilesComponent = new JList(files.toArray()) {
|
JList existingFilesComponent = new JList(files.toArray()) {
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final Action downloadAction = new AbstractAction("Download", ResourceManager.getIcon("dialog.continue")) {
|
private final Action downloadAction = new AbstractAction("Download", ResourceManager.getIcon("dialog.continue")) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -361,17 +361,17 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleMappingOptionRenderer extends DefaultTableCellRenderer {
|
private static class SubtitleMappingOptionRenderer extends DefaultTableCellRenderer {
|
||||||
|
|
||||||
private final JComboBox optionComboBox = new SimpleComboBox();
|
private final JComboBox optionComboBox = new SimpleComboBox();
|
||||||
|
|
||||||
|
|
||||||
public SubtitleMappingOptionRenderer() {
|
public SubtitleMappingOptionRenderer() {
|
||||||
optionComboBox.setRenderer(new SubtitleOptionRenderer());
|
optionComboBox.setRenderer(new SubtitleOptionRenderer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||||
SubtitleMapping mapping = (SubtitleMapping) value;
|
SubtitleMapping mapping = (SubtitleMapping) value;
|
||||||
@ -413,12 +413,12 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleOptionRenderer extends DefaultListCellRenderer {
|
private static class SubtitleOptionRenderer extends DefaultListCellRenderer {
|
||||||
|
|
||||||
private final Border padding = createEmptyBorder(3, 3, 3, 3);
|
private final Border padding = createEmptyBorder(3, 3, 3, 3);
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
super.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus);
|
super.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus);
|
||||||
@ -444,14 +444,14 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleMappingTableModel extends AbstractTableModel implements Iterable<SubtitleMapping> {
|
private static class SubtitleMappingTableModel extends AbstractTableModel implements Iterable<SubtitleMapping> {
|
||||||
|
|
||||||
private final SubtitleMapping[] data;
|
private final SubtitleMapping[] data;
|
||||||
|
|
||||||
private boolean optionColumnVisible = false;
|
private boolean optionColumnVisible = false;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleMappingTableModel(File... videoFiles) {
|
public SubtitleMappingTableModel(File... videoFiles) {
|
||||||
data = new SubtitleMapping[videoFiles.length];
|
data = new SubtitleMapping[videoFiles.length];
|
||||||
|
|
||||||
@ -461,7 +461,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<File> getVideoFiles() {
|
public List<File> getVideoFiles() {
|
||||||
return new AbstractList<File>() {
|
return new AbstractList<File>() {
|
||||||
|
|
||||||
@ -470,7 +470,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return data[index].getVideoFile();
|
return data[index].getVideoFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return data.length;
|
return data.length;
|
||||||
@ -478,13 +478,13 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<SubtitleMapping> iterator() {
|
public Iterator<SubtitleMapping> iterator() {
|
||||||
return Arrays.asList(data).iterator();
|
return Arrays.asList(data).iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setOptionColumnVisible(boolean optionColumnVisible) {
|
public void setOptionColumnVisible(boolean optionColumnVisible) {
|
||||||
if (this.optionColumnVisible == optionColumnVisible)
|
if (this.optionColumnVisible == optionColumnVisible)
|
||||||
return;
|
return;
|
||||||
@ -495,13 +495,13 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
fireTableStructureChanged();
|
fireTableStructureChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColumnCount() {
|
public int getColumnCount() {
|
||||||
return optionColumnVisible ? 2 : 1;
|
return optionColumnVisible ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName(int column) {
|
public String getColumnName(int column) {
|
||||||
switch (column) {
|
switch (column) {
|
||||||
@ -514,13 +514,13 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
return data.length;
|
return data.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int row, int column) {
|
public Object getValueAt(int row, int column) {
|
||||||
switch (column) {
|
switch (column) {
|
||||||
@ -533,19 +533,19 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValueAt(Object value, int row, int column) {
|
public void setValueAt(Object value, int row, int column) {
|
||||||
data[row].setSelectedOption((SubtitleDescriptorBean) value);
|
data[row].setSelectedOption((SubtitleDescriptorBean) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCellEditable(int row, int column) {
|
public boolean isCellEditable(int row, int column) {
|
||||||
return column == 1 && data[row].isEditable();
|
return column == 1 && data[row].isEditable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getColumnClass(int column) {
|
public Class<?> getColumnClass(int column) {
|
||||||
switch (column) {
|
switch (column) {
|
||||||
@ -558,17 +558,17 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class SubtitleMappingListener implements PropertyChangeListener {
|
private class SubtitleMappingListener implements PropertyChangeListener {
|
||||||
|
|
||||||
private final int index;
|
private final int index;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleMappingListener(int index) {
|
public SubtitleMappingListener(int index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
// update state and subtitle options
|
// update state and subtitle options
|
||||||
@ -577,7 +577,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleMapping extends AbstractBean {
|
private static class SubtitleMapping extends AbstractBean {
|
||||||
|
|
||||||
private File videoFile;
|
private File videoFile;
|
||||||
@ -586,38 +586,38 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
private SubtitleDescriptorBean selectedOption;
|
private SubtitleDescriptorBean selectedOption;
|
||||||
private List<SubtitleDescriptorBean> options = new ArrayList<SubtitleDescriptorBean>();
|
private List<SubtitleDescriptorBean> options = new ArrayList<SubtitleDescriptorBean>();
|
||||||
|
|
||||||
|
|
||||||
public SubtitleMapping(File videoFile) {
|
public SubtitleMapping(File videoFile) {
|
||||||
this.videoFile = videoFile;
|
this.videoFile = videoFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public File getVideoFile() {
|
public File getVideoFile() {
|
||||||
return videoFile;
|
return videoFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public File getSubtitleFile() {
|
public File getSubtitleFile() {
|
||||||
return subtitleFile;
|
return subtitleFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setSubtitleFile(File subtitleFile) {
|
public void setSubtitleFile(File subtitleFile) {
|
||||||
this.subtitleFile = subtitleFile;
|
this.subtitleFile = subtitleFile;
|
||||||
firePropertyChange("subtitleFile", null, this.subtitleFile);
|
firePropertyChange("subtitleFile", null, this.subtitleFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isEditable() {
|
public boolean isEditable() {
|
||||||
return subtitleFile == null && selectedOption != null && (selectedOption.getState() == null || selectedOption.getError() != null);
|
return subtitleFile == null && selectedOption != null && (selectedOption.getState() == null || selectedOption.getError() != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SubtitleDescriptorBean getSelectedOption() {
|
public SubtitleDescriptorBean getSelectedOption() {
|
||||||
return selectedOption;
|
return selectedOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setSelectedOption(SubtitleDescriptorBean selectedOption) {
|
public void setSelectedOption(SubtitleDescriptorBean selectedOption) {
|
||||||
if (this.selectedOption != null) {
|
if (this.selectedOption != null) {
|
||||||
this.selectedOption.removePropertyChangeListener(selectedOptionListener);
|
this.selectedOption.removePropertyChangeListener(selectedOptionListener);
|
||||||
@ -629,12 +629,12 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
firePropertyChange("selectedOption", null, this.selectedOption);
|
firePropertyChange("selectedOption", null, this.selectedOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SubtitleDescriptorBean[] getOptions() {
|
public SubtitleDescriptorBean[] getOptions() {
|
||||||
return options.toArray(new SubtitleDescriptorBean[0]);
|
return options.toArray(new SubtitleDescriptorBean[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addOptions(List<SubtitleDescriptorBean> options) {
|
public void addOptions(List<SubtitleDescriptorBean> options) {
|
||||||
this.options.addAll(options);
|
this.options.addAll(options);
|
||||||
|
|
||||||
@ -643,7 +643,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final PropertyChangeListener selectedOptionListener = new PropertyChangeListener() {
|
private final PropertyChangeListener selectedOptionListener = new PropertyChangeListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -653,7 +653,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SubtitleDescriptorBean extends AbstractBean {
|
private static class SubtitleDescriptorBean extends AbstractBean {
|
||||||
|
|
||||||
private final File videoFile;
|
private final File videoFile;
|
||||||
@ -663,39 +663,39 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
private StateValue state;
|
private StateValue state;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleDescriptorBean(File videoFile, SubtitleDescriptor descriptor, SubtitleServiceBean service) {
|
public SubtitleDescriptorBean(File videoFile, SubtitleDescriptor descriptor, SubtitleServiceBean service) {
|
||||||
this.videoFile = videoFile;
|
this.videoFile = videoFile;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
this.service = service;
|
this.service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public float getMatchProbability() {
|
public float getMatchProbability() {
|
||||||
return service.getMatchProbabilty(videoFile, descriptor);
|
return service.getMatchProbabilty(videoFile, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return formatSubtitle(descriptor.getName(), getLanguageName(), getType());
|
return formatSubtitle(descriptor.getName(), getLanguageName(), getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Icon getIcon() {
|
public Icon getIcon() {
|
||||||
return service.getIcon();
|
return service.getIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getLanguageName() {
|
public String getLanguageName() {
|
||||||
return descriptor.getLanguageName();
|
return descriptor.getLanguageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return descriptor.getType();
|
return descriptor.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public MemoryFile fetch() throws Exception {
|
public MemoryFile fetch() throws Exception {
|
||||||
setState(StateValue.STARTED);
|
setState(StateValue.STARTED);
|
||||||
|
|
||||||
@ -715,30 +715,30 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Exception getError() {
|
public Exception getError() {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public StateValue getState() {
|
public StateValue getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setState(StateValue state) {
|
public void setState(StateValue state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
firePropertyChange("state", null, this.state);
|
firePropertyChange("state", null, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getText();
|
return getText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class QueryTask extends SwingWorker<Collection<File>, Map<File, List<SubtitleDescriptorBean>>> {
|
private static class QueryTask extends SwingWorker<Collection<File>, Map<File, List<SubtitleDescriptorBean>>> {
|
||||||
|
|
||||||
private final Component parent;
|
private final Component parent;
|
||||||
@ -747,7 +747,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
private final Collection<File> remainingVideos;
|
private final Collection<File> remainingVideos;
|
||||||
private final String languageName;
|
private final String languageName;
|
||||||
|
|
||||||
|
|
||||||
public QueryTask(Collection<SubtitleServiceBean> services, Collection<File> videoFiles, String languageName, Component parent) {
|
public QueryTask(Collection<SubtitleServiceBean> services, Collection<File> videoFiles, String languageName, Component parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.services = services;
|
this.services = services;
|
||||||
@ -755,7 +755,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
this.languageName = languageName;
|
this.languageName = languageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection<File> doInBackground() throws Exception {
|
protected Collection<File> doInBackground() throws Exception {
|
||||||
for (SubtitleServiceBean service : services) {
|
for (SubtitleServiceBean service : services) {
|
||||||
@ -804,24 +804,24 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class DownloadTask extends SwingWorker<File, Void> {
|
private static class DownloadTask extends SwingWorker<File, Void> {
|
||||||
|
|
||||||
private final File video;
|
private final File video;
|
||||||
private final SubtitleDescriptorBean descriptor;
|
private final SubtitleDescriptorBean descriptor;
|
||||||
|
|
||||||
|
|
||||||
public DownloadTask(File video, SubtitleDescriptorBean descriptor) {
|
public DownloadTask(File video, SubtitleDescriptorBean descriptor) {
|
||||||
this.video = video;
|
this.video = video;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SubtitleDescriptorBean getSubtitleBean() {
|
public SubtitleDescriptorBean getSubtitleBean() {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public File getDestination(MemoryFile subtitle) {
|
public File getDestination(MemoryFile subtitle) {
|
||||||
if (descriptor.getType() == null && subtitle == null)
|
if (descriptor.getType() == null && subtitle == null)
|
||||||
return null;
|
return null;
|
||||||
@ -832,7 +832,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return new File(video.getParentFile(), formatSubtitle(base, descriptor.getLanguageName(), ext));
|
return new File(video.getParentFile(), formatSubtitle(base, descriptor.getLanguageName(), ext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected File doInBackground() {
|
protected File doInBackground() {
|
||||||
try {
|
try {
|
||||||
@ -855,7 +855,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static abstract class SubtitleServiceBean extends AbstractBean {
|
protected static abstract class SubtitleServiceBean extends AbstractBean {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
@ -865,35 +865,35 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
private StateValue state = StateValue.PENDING;
|
private StateValue state = StateValue.PENDING;
|
||||||
private Throwable error = null;
|
private Throwable error = null;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleServiceBean(String name, Icon icon, URI link) {
|
public SubtitleServiceBean(String name, Icon icon, URI link) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
this.link = link;
|
this.link = link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Icon getIcon() {
|
public Icon getIcon() {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public URI getLink() {
|
public URI getLink() {
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor);
|
public abstract float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor);
|
||||||
|
|
||||||
|
|
||||||
protected abstract Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception;
|
protected abstract Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public final Map<File, List<SubtitleDescriptor>> lookupSubtitles(Collection<File> files, String languageName, Component parent) throws Exception {
|
public final Map<File, List<SubtitleDescriptor>> lookupSubtitles(Collection<File> files, String languageName, Component parent) throws Exception {
|
||||||
setState(StateValue.STARTED);
|
setState(StateValue.STARTED);
|
||||||
|
|
||||||
@ -910,61 +910,61 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setState(StateValue state) {
|
private void setState(StateValue state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
firePropertyChange("state", null, this.state);
|
firePropertyChange("state", null, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public StateValue getState() {
|
public StateValue getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Throwable getError() {
|
public Throwable getError() {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static class VideoHashSubtitleServiceBean extends SubtitleServiceBean {
|
protected static class VideoHashSubtitleServiceBean extends SubtitleServiceBean {
|
||||||
|
|
||||||
private VideoHashSubtitleService service;
|
private VideoHashSubtitleService service;
|
||||||
|
|
||||||
|
|
||||||
public VideoHashSubtitleServiceBean(VideoHashSubtitleService service) {
|
public VideoHashSubtitleServiceBean(VideoHashSubtitleService service) {
|
||||||
super(service.getName(), service.getIcon(), service.getLink());
|
super(service.getName(), service.getIcon(), service.getLink());
|
||||||
this.service = service;
|
this.service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception {
|
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception {
|
||||||
return service.getSubtitleList(files.toArray(new File[0]), languageName);
|
return service.getSubtitleList(files.toArray(new File[0]), languageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor) {
|
public float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static class SubtitleProviderBean extends SubtitleServiceBean {
|
protected static class SubtitleProviderBean extends SubtitleServiceBean {
|
||||||
|
|
||||||
private SubtitleAutoMatchDialog inputProvider;
|
private SubtitleAutoMatchDialog inputProvider;
|
||||||
private SubtitleProvider service;
|
private SubtitleProvider service;
|
||||||
|
|
||||||
|
|
||||||
public SubtitleProviderBean(SubtitleProvider service, SubtitleAutoMatchDialog inputProvider) {
|
public SubtitleProviderBean(SubtitleProvider service, SubtitleAutoMatchDialog inputProvider) {
|
||||||
super(service.getName(), service.getIcon(), service.getLink());
|
super(service.getName(), service.getIcon(), service.getLink());
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.inputProvider = inputProvider;
|
this.inputProvider = inputProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception {
|
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception {
|
||||||
Map<File, List<SubtitleDescriptor>> subtitlesByFile = new HashMap<File, List<SubtitleDescriptor>>();
|
Map<File, List<SubtitleDescriptor>> subtitlesByFile = new HashMap<File, List<SubtitleDescriptor>>();
|
||||||
@ -973,7 +973,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// auto-detect query and search for subtitles
|
// auto-detect query and search for subtitles
|
||||||
Collection<String> querySet = detectSeriesName(files);
|
Collection<String> querySet = detectSeriesNames(files);
|
||||||
List<SubtitleDescriptor> subtitles = findSubtitles(service, querySet, languageName);
|
List<SubtitleDescriptor> subtitles = findSubtitles(service, querySet, languageName);
|
||||||
|
|
||||||
// if auto-detection fails, ask user for input
|
// if auto-detection fails, ask user for input
|
||||||
@ -1016,7 +1016,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||||||
return subtitlesByFile;
|
return subtitlesByFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor) {
|
public float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor) {
|
||||||
return EpisodeMetrics.verificationMetric().getSimilarity(videoFile, descriptor) * 0.9f;
|
return EpisodeMetrics.verificationMetric().getSimilarity(videoFile, descriptor) * 0.9f;
|
||||||
|
Loading…
Reference in New Issue
Block a user