mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-24 16:58:51 -05:00
+ 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:
parent
bf6cccfbbb
commit
a248021ebf
@ -284,6 +284,26 @@ public enum EpisodeMetrics implements SimilarityMetric {
|
|||||||
|
|
||||||
return null;
|
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
|
// inner metric
|
||||||
@ -338,11 +358,12 @@ public enum EpisodeMetrics implements SimilarityMetric {
|
|||||||
// 4 pass: divide by folder / file name and show name / episode title
|
// 4 pass: divide by folder / file name and show name / episode title
|
||||||
// 5 pass: divide by name (rounded into n levels)
|
// 5 pass: divide by name (rounded into n levels)
|
||||||
// 6 pass: divide by generic numeric similarity
|
// 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) {
|
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 {
|
} 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() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,9 +3,8 @@ package net.sourceforge.filebot.subtitle;
|
|||||||
|
|
||||||
|
|
||||||
import static java.lang.Math.*;
|
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.MediaTypes.*;
|
||||||
|
import static net.sourceforge.filebot.similarity.EpisodeMetrics.*;
|
||||||
import static net.sourceforge.filebot.similarity.Normalization.*;
|
import static net.sourceforge.filebot.similarity.Normalization.*;
|
||||||
import static net.sourceforge.tuned.FileUtilities.*;
|
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.Match;
|
||||||
import net.sourceforge.filebot.similarity.Matcher;
|
import net.sourceforge.filebot.similarity.Matcher;
|
||||||
import net.sourceforge.filebot.similarity.MetricAvg;
|
import net.sourceforge.filebot.similarity.MetricAvg;
|
||||||
|
import net.sourceforge.filebot.similarity.MetricCascade;
|
||||||
import net.sourceforge.filebot.similarity.NameSimilarityMetric;
|
import net.sourceforge.filebot.similarity.NameSimilarityMetric;
|
||||||
import net.sourceforge.filebot.similarity.SequenceMatchSimilarity;
|
import net.sourceforge.filebot.similarity.SequenceMatchSimilarity;
|
||||||
import net.sourceforge.filebot.similarity.SimilarityMetric;
|
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 {
|
public static Map<File, SubtitleDescriptor> matchSubtitles(Collection<File> files, Collection<SubtitleDescriptor> subtitles, boolean strict) throws InterruptedException {
|
||||||
Map<File, SubtitleDescriptor> subtitleByVideo = new LinkedHashMap<File, SubtitleDescriptor>();
|
Map<File, SubtitleDescriptor> subtitleByVideo = new LinkedHashMap<File, SubtitleDescriptor>();
|
||||||
|
|
||||||
SimilarityMetric[] metrics = EpisodeMetrics.defaultSequence(false);
|
|
||||||
|
|
||||||
// optimize for generic media <-> subtitle matching
|
// 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
|
// first match everything as best as possible, then filter possibly bad matches
|
||||||
Matcher<File, SubtitleDescriptor> matcher = new Matcher<File, SubtitleDescriptor>(files, subtitles, false, metrics);
|
Matcher<File, SubtitleDescriptor> matcher = new Matcher<File, SubtitleDescriptor>(files, subtitles, false, metrics);
|
||||||
|
@ -21,34 +21,39 @@ public class Date implements Serializable {
|
|||||||
private int month;
|
private int month;
|
||||||
private int day;
|
private int day;
|
||||||
|
|
||||||
|
|
||||||
protected Date() {
|
protected Date() {
|
||||||
// used by serializer
|
// used by serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Date(int year, int month, int day) {
|
public Date(int year, int month, int day) {
|
||||||
this.year = year;
|
this.year = year;
|
||||||
this.month = month;
|
this.month = month;
|
||||||
this.day = day;
|
this.day = day;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getYear() {
|
public int getYear() {
|
||||||
return year;
|
return year;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getMonth() {
|
public int getMonth() {
|
||||||
return month;
|
return month;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getDay() {
|
public int getDay() {
|
||||||
return day;
|
return day;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public long getTimeStamp() {
|
||||||
|
return new GregorianCalendar(year, month, day).getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj instanceof Date) {
|
if (obj instanceof Date) {
|
||||||
@ -59,29 +64,29 @@ public class Date implements Serializable {
|
|||||||
return super.equals(obj);
|
return super.equals(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Arrays.hashCode(new Object[] { year, month, day });
|
return Arrays.hashCode(new Object[] { year, month, day });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%04d-%02d-%02d", year, month, day);
|
return String.format("%04d-%02d-%02d", year, month, day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String format(String pattern) {
|
public String format(String pattern) {
|
||||||
return format(pattern, Locale.ROOT);
|
return format(pattern, Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String format(String pattern, Locale locale) {
|
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
|
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) {
|
public static Date parse(String string, String pattern) {
|
||||||
if (string == null || string.isEmpty())
|
if (string == null || string.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
Loading…
Reference in New Issue
Block a user