+ ReleaseDate metric matching step for differentiating multiple shows with the same name, usually nudging things towards the more recent episode/series.

This commit is contained in:
Reinhard Pointner 2012-10-09 13:30:32 +00:00
parent bf6cccfbbb
commit a248021ebf
4 changed files with 81 additions and 19 deletions

View File

@ -284,6 +284,26 @@ public enum EpisodeMetrics implements SimilarityMetric {
return null;
}
}),
// Match by file last modified and episode release dates
TimeStamp(new TimeStampMetric() {
@Override
public float getSimilarity(Object o1, Object o2) {
// adjust differentiation accuracy to about a year
return (float) (floor(super.getSimilarity(o1, o2) * 40) / 40);
}
@Override
public long getTimeStamp(Object object) {
if (object instanceof Episode) {
return ((Episode) object).airdate().getTimeStamp();
}
return super.getTimeStamp(object);
}
});
// inner metric
@ -338,11 +358,12 @@ public enum EpisodeMetrics implements SimilarityMetric {
// 4 pass: divide by folder / file name and show name / episode title
// 5 pass: divide by name (rounded into n levels)
// 6 pass: divide by generic numeric similarity
// 7 pass: resolve remaining collisions via absolute string similarity
// 7 pass: prefer episodes that were aired closer to the last modified date of the file
// 8 pass: resolve remaining collisions via absolute string similarity
if (includeFileMetrics) {
return new SimilarityMetric[] { FileSize, new MetricCascade(FileName, EpisodeFunnel), EpisodeBalancer, SubstringFields, new MetricCascade(SubstringSequence, Name), Numeric, new NameSimilarityMetric() };
return new SimilarityMetric[] { FileSize, new MetricCascade(FileName, EpisodeFunnel), EpisodeBalancer, SubstringFields, new MetricCascade(SubstringSequence, Name), Numeric, Name, TimeStamp, new NameSimilarityMetric() };
} else {
return new SimilarityMetric[] { EpisodeFunnel, EpisodeBalancer, SubstringFields, new MetricCascade(SubstringSequence, Name), Numeric, new NameSimilarityMetric() };
return new SimilarityMetric[] { EpisodeFunnel, EpisodeBalancer, SubstringFields, new MetricCascade(SubstringSequence, Name), Numeric, Name, TimeStamp, new NameSimilarityMetric() };
}
}

View File

@ -0,0 +1,38 @@
package net.sourceforge.filebot.similarity;
import static java.lang.Math.*;
import java.io.File;
public class TimeStampMetric implements SimilarityMetric {
@Override
public float getSimilarity(Object o1, Object o2) {
long t1 = getTimeStamp(o1);
long t2 = getTimeStamp(o2);
if (t1 <= 0 || t2 <= 0)
return 0;
float min = min(t1, t2);
float max = max(t1, t2);
return min / max;
}
public long getTimeStamp(Object obj) {
if (obj instanceof File) {
return ((File) obj).lastModified();
}
if (obj instanceof Number) {
return ((Number) obj).longValue();
}
return -1;
}
}

View File

@ -3,9 +3,8 @@ package net.sourceforge.filebot.subtitle;
import static java.lang.Math.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;
import static net.sourceforge.filebot.MediaTypes.*;
import static net.sourceforge.filebot.similarity.EpisodeMetrics.*;
import static net.sourceforge.filebot.similarity.Normalization.*;
import static net.sourceforge.tuned.FileUtilities.*;
@ -30,6 +29,7 @@ import net.sourceforge.filebot.similarity.EpisodeMetrics;
import net.sourceforge.filebot.similarity.Match;
import net.sourceforge.filebot.similarity.Matcher;
import net.sourceforge.filebot.similarity.MetricAvg;
import net.sourceforge.filebot.similarity.MetricCascade;
import net.sourceforge.filebot.similarity.NameSimilarityMetric;
import net.sourceforge.filebot.similarity.SequenceMatchSimilarity;
import net.sourceforge.filebot.similarity.SimilarityMetric;
@ -46,10 +46,8 @@ public final class SubtitleUtilities {
public static Map<File, SubtitleDescriptor> matchSubtitles(Collection<File> files, Collection<SubtitleDescriptor> subtitles, boolean strict) throws InterruptedException {
Map<File, SubtitleDescriptor> subtitleByVideo = new LinkedHashMap<File, SubtitleDescriptor>();
SimilarityMetric[] metrics = EpisodeMetrics.defaultSequence(false);
// optimize for generic media <-> subtitle matching
replaceAll(asList(metrics), EpisodeMetrics.SubstringFields, EpisodeMetrics.SubstringSequence);
SimilarityMetric[] metrics = new SimilarityMetric[] { EpisodeFunnel, EpisodeBalancer, SubstringSequence, new MetricCascade(SubstringSequence, Name), Numeric, new NameSimilarityMetric() };
// first match everything as best as possible, then filter possibly bad matches
Matcher<File, SubtitleDescriptor> matcher = new Matcher<File, SubtitleDescriptor>(files, subtitles, false, metrics);

View File

@ -21,34 +21,39 @@ public class Date implements Serializable {
private int month;
private int day;
protected Date() {
// used by serializer
}
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public int getMonth() {
return month;
}
public int getDay() {
return day;
}
public long getTimeStamp() {
return new GregorianCalendar(year, month, day).getTimeInMillis();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Date) {
@ -59,29 +64,29 @@ public class Date implements Serializable {
return super.equals(obj);
}
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] { year, month, day });
}
@Override
public String toString() {
return String.format("%04d-%02d-%02d", year, month, day);
}
public String format(String pattern) {
return format(pattern, Locale.ROOT);
}
public String format(String pattern, Locale locale) {
return new SimpleDateFormat(pattern, locale).format(new GregorianCalendar(year, month - 1, day).getTime()); // Calendar months start at 0
}
public static Date parse(String string, String pattern) {
if (string == null || string.isEmpty())
return null;