* add support for absolute episode numbers alongside SxE

-> add absolute episode number support to TVRage and TheTVDB
-> check against absolute episode number when matching files and episodes
-> add naming scheme binding for absolute episode number
This commit is contained in:
Reinhard Pointner 2010-11-09 08:04:12 +00:00
parent 78d2a3c44a
commit 13a1b3fa6a
16 changed files with 95 additions and 30 deletions

View File

@ -70,12 +70,24 @@ public class EpisodeBindingBean {
}
@Define("air")
@Define("airdate")
public Date airdate() {
return episode.airdate();
}
@Define("absolute")
public Integer getAbsoluteEpisodeNumber() {
return episode.getAbsolute();
}
@Define("special")
public Integer getSpecialNumber() {
return episode.getSpecial();
}
@Define("vc")
public String getVideoCodec() {
// e.g. XviD, x264, DivX 5, MPEG-4 Visual, AVC, etc.

View File

@ -35,10 +35,10 @@ public class SeasonEpisodeMatcher {
SxE seasonEpisode = new SxE(match.group(1), match.group(2));
// interpret match as episode number only
SxE episodeOnly = new SxE(null, match.group(1) + match.group(2));
SxE absoluteEpisode = new SxE(null, match.group(1) + match.group(2));
// return both matches, unless they are one and the same
return seasonEpisode.equals(episodeOnly) ? Collections.singleton(episodeOnly) : Arrays.asList(seasonEpisode, episodeOnly);
return seasonEpisode.equals(absoluteEpisode) ? Collections.singleton(absoluteEpisode) : Arrays.asList(seasonEpisode, absoluteEpisode);
}
};
}

View File

@ -27,12 +27,12 @@ public class SeasonEpisodeMetric implements SimilarityMetric {
for (SxE sxe1 : sxeVector1) {
for (SxE sxe2 : sxeVector2) {
if (sxe1.episode == sxe2.episode && sxe1.season == sxe2.season) {
if (sxe1.season == sxe2.season && sxe1.episode == sxe2.episode) {
// vectors have at least one perfect episode match in common
return 1;
}
if (sxe1.episode == sxe2.episode || sxe1.season == sxe2.season) {
if (sxe1.season == sxe2.season || sxe1.episode == sxe2.episode) {
// at least we have a partial match
similarity = 0.5f;
}

View File

@ -8,8 +8,10 @@ expr[a1]: n
expr[a2]: s
expr[a3]: e
expr[a4]: t
expr[a5]: air
expr[a6]: episode
expr[a5]: airdate
expr[a6]: absolute
expr[a7]: special
expr[a8]: episode
# simple mediainfo expressions
expr[b1]: vc

View File

@ -291,7 +291,7 @@ class EpisodeFormatDialog extends JDialog {
episode = EpisodeFormat.getDefaultInstance().parseObject(persistentSampleEpisode.getValue());
} catch (Exception e) {
// default sample
episode = new Episode("Dark Angel", 3, 1, "Labyrinth", null, new Date(2009, 6, 1));
episode = new Episode("Dark Angel", 3, 1, "Labyrinth", 42, null, new Date(2009, 6, 1));
}
// restore media file

View File

@ -2,11 +2,12 @@
package net.sourceforge.filebot.ui.panel.rename;
import static java.util.Collections.*;
import static net.sourceforge.filebot.hash.VerificationUtilities.*;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import net.sourceforge.filebot.similarity.DateMetric;
import net.sourceforge.filebot.similarity.FileSizeMetric;
@ -27,7 +28,7 @@ public enum MatchSimilarityMetric implements SimilarityMetric {
@Override
public float getSimilarity(Object o1, Object o2) {
// order of arguments is logically irrelevant, but we might be able to save us a call to File.length() this way
// order of arguments is logically irrelevant, but we might be able to save us a call to File.length() which is quite costly
return o1 instanceof File ? super.getSimilarity(o2, o1) : super.getSimilarity(o1, o2);
}
@ -47,7 +48,13 @@ public enum MatchSimilarityMetric implements SimilarityMetric {
@Override
public float getSimilarity(Object o1, Object o2) {
return Math.max(SeasonEpisode.getSimilarity(o1, o2), AirDate.getSimilarity(o1, o2));
float sxeSimilarity = SeasonEpisode.getSimilarity(o1, o2);
// break if SxE is a perfect match already
if (sxeSimilarity >= 1)
return sxeSimilarity;
return Math.max(sxeSimilarity, AirDate.getSimilarity(o1, o2));
}
}),
@ -60,8 +67,11 @@ public enum MatchSimilarityMetric implements SimilarityMetric {
if (object instanceof Episode) {
Episode episode = (Episode) object;
// create SxE from episode
return singleton(new SxE(episode.getSeason(), episode.getEpisode()));
// get SxE from episode, both SxE for season/episode numbering and SxE for absolute episode numbering
SxE seasonEpisode = new SxE(episode.getSeason(), episode.getEpisode());
SxE absoluteEpisode = new SxE(null, episode.getAbsolute());
return seasonEpisode.equals(absoluteEpisode) ? Collections.singleton(absoluteEpisode) : Arrays.asList(seasonEpisode, absoluteEpisode);
}
return super.parse(object);

View File

@ -149,7 +149,7 @@ public class AnidbClient implements EpisodeListProvider {
String airdate = selectString(".//date/@rel", node);
// no seasons for anime
episodes.add(new Episode(animeTitle, null, number, title, null, Date.parse(airdate, "yyyy-MM-dd")));
episodes.add(new Episode(animeTitle, null, number, title, number, null, Date.parse(airdate, "yyyy-MM-dd")));
}
}

View File

@ -13,6 +13,9 @@ public class Episode implements Serializable {
private Integer episode;
private String title;
// absolute episode number
private Integer absolute;
// special number
private Integer special;
@ -26,15 +29,16 @@ public class Episode implements Serializable {
public Episode(String seriesName, Integer season, Integer episode, String title) {
this(seriesName, season, episode, title, null, null);
this(seriesName, season, episode, title, null, null, null);
}
public Episode(String seriesName, Integer season, Integer episode, String title, Integer special, Date airdate) {
public Episode(String seriesName, Integer season, Integer episode, String title, Integer absolute, Integer special, Date airdate) {
this.seriesName = seriesName;
this.season = season;
this.episode = episode;
this.title = title;
this.absolute = absolute;
this.special = special;
this.airdate = airdate;
}
@ -60,6 +64,11 @@ public class Episode implements Serializable {
}
public Integer getAbsolute() {
return absolute;
}
public Integer getSpecial() {
return special;
}

View File

@ -88,7 +88,7 @@ public class EpisodeFormat extends Format {
}
if ((m = sxePattern.matcher(source)).find()) {
season = new Integer(m.group(1));
season = (m.group(1) == null) ? null : new Integer(m.group(1));
if (m.group(2) == null)
episode = new Integer(m.group(3));
else
@ -102,7 +102,7 @@ public class EpisodeFormat extends Format {
// did parse input
pos.setIndex(source.length());
return new Episode(name, season, episode, title, special, airdate);
return new Episode(name, season, episode, title, season == null ? episode : null, special, airdate);
}
// failed to parse input

View File

@ -106,7 +106,7 @@ public class IMDbClient implements EpisodeListProvider {
// e.g. 20 May 2003
String airdate = selectString("./following::STRONG", node);
episodes.add(new Episode(seriesName, season, episode, title, null, Date.parse(airdate, "dd MMMMM yyyyy")));
episodes.add(new Episode(seriesName, season, episode, title, null, null, Date.parse(airdate, "dd MMMMM yyyyy")));
}
return episodes;

View File

@ -177,7 +177,7 @@ public class TVDotComClient implements EpisodeListProvider {
// add episode if SxE info has been found
if (season != null && episode != null) {
episodes.add(new Episode(searchResult.getName(), season, episode, title, null, airdate));
episodes.add(new Episode(searchResult.getName(), season, episode, title, null, null, airdate));
}
}

View File

@ -86,6 +86,7 @@ public class TVRageClient implements EpisodeListProvider {
for (Node node : selectNodes("//episode", dom)) {
String title = getTextContent("title", node);
Integer episodeNumber = getIntegerContent("seasonnum", node);
Integer absoluteNumber = getIntegerContent("epnum", node);
String seasonIdentifier = getAttribute("no", node.getParentNode());
Integer seasonNumber = seasonIdentifier == null ? null : new Integer(seasonIdentifier);
Date airdate = Date.parse(getTextContent("airdate", node), "yyyy-MM-dd");
@ -95,10 +96,10 @@ public class TVRageClient implements EpisodeListProvider {
// handle as special episode
seasonNumber = getIntegerContent("season", node);
int specialNumber = filterBySeason(specials, seasonNumber).size() + 1;
specials.add(new Episode(seriesName, seasonNumber, null, title, specialNumber, airdate));
specials.add(new Episode(seriesName, seasonNumber, null, title, null, specialNumber, airdate));
} else {
// handle as normal episode
episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, title, null, airdate));
episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, title, absoluteNumber, null, airdate));
}
}

View File

@ -79,6 +79,13 @@ public class TheTVDBClient implements EpisodeListProvider {
public List<SearchResult> search(String query, Locale language) throws Exception {
// check if the exact series name is already cached
Integer cachedResult = cache.getSeriesId(query, language);
if (cachedResult != null)
return Arrays.asList(new SearchResult[] { new TheTVDBSearchResult(query, cachedResult) });
// perform online search
URL url = getResource(null, "/api/GetSeries.php?seriesname=" + URLEncoder.encode(query, "UTF-8") + "&language=" + language.getLanguage());
Document dom = getDocument(url);
@ -86,10 +93,11 @@ public class TheTVDBClient implements EpisodeListProvider {
List<SearchResult> searchResults = new ArrayList<SearchResult>(nodes.size());
for (Node node : nodes) {
int seriesId = Integer.parseInt(getTextContent("seriesid", node));
int seriesId = getIntegerContent("seriesid", node);
String seriesName = getTextContent("SeriesName", node);
searchResults.add(new TheTVDBSearchResult(seriesName, seriesId));
cache.putSeriesId(seriesName, language, seriesId);
}
return searchResults;
@ -134,6 +142,7 @@ public class TheTVDBClient implements EpisodeListProvider {
for (Node node : nodes) {
String episodeName = getTextContent("EpisodeName", node);
Integer episodeNumber = getIntegerContent("EpisodeNumber", node);
Integer absoluteNumber = getIntegerContent("absolute_number", node);
Integer seasonNumber = getIntegerContent("SeasonNumber", node);
Date airdate = Date.parse(getTextContent("FirstAired", node), "yyyy-MM-dd");
@ -145,10 +154,10 @@ public class TheTVDBClient implements EpisodeListProvider {
}
Integer specialNumber = filterBySeason(specials, seasonNumber).size() + 1;
specials.add(new Episode(seriesName, seasonNumber, null, episodeName, specialNumber, airdate));
specials.add(new Episode(seriesName, seasonNumber, null, episodeName, null, specialNumber, airdate));
} else {
// handle as normal episode
episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, episodeName, null, airdate));
episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate));
}
if (episodeNumber == 1) {
@ -338,13 +347,28 @@ public class TheTVDBClient implements EpisodeListProvider {
}
public void putSeriesId(String seriesName, Locale language, int seriesId) {
cache.put(new Element(key(host, "SeriesId", seriesName, language.getLanguage()), seriesId));
}
public Integer getSeriesId(String seriesName, Locale language) {
Element element = cache.get(key(host, "SeriesId", seriesName, language.getLanguage()));
if (element != null)
return (Integer) element.getValue();
return null;
}
public void putSeasonId(int seriesId, int seasonNumber, int seasonId) {
cache.put(new Element(key(host, seriesId, seasonNumber, "SeasonId"), seasonId));
cache.put(new Element(key(host, "SeasonId", seriesId, seasonNumber), seasonId));
}
public Integer getSeasonId(int seriesId, int seasonNumber) {
Element element = cache.get(key(host, seriesId, seasonNumber, "SeasonId"));
Element element = cache.get(key(host, "SeasonId", seriesId, seasonNumber));
if (element != null)
return (Integer) element.getValue();
@ -354,13 +378,13 @@ public class TheTVDBClient implements EpisodeListProvider {
public void putEpisodeList(int seriesId, Locale language, List<Episode> episodes) {
cache.put(new Element(key(host, seriesId, language.getLanguage(), "EpisodeList"), episodes));
cache.put(new Element(key(host, "EpisodeList", seriesId, language.getLanguage()), episodes));
}
@SuppressWarnings("unchecked")
public List<Episode> getEpisodeList(int seriesId, Locale language) {
Element element = cache.get(key(host, seriesId, language.getLanguage(), "EpisodeList"));
Element element = cache.get(key(host, "EpisodeList", seriesId, language.getLanguage()));
if (element != null)
return (List<Episode>) element.getValue();

View File

@ -84,6 +84,7 @@ public class AnidbClientTest {
assertEquals("Monster", first.getSeriesName());
assertEquals("Herr Dr. Tenma", first.getTitle());
assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getAbsolute().toString());
assertEquals(null, first.getSeason());
assertEquals("2004-04-07", first.airdate().toString());
}
@ -97,9 +98,10 @@ public class AnidbClientTest {
Episode first = list.get(0);
assertEquals("Juuni Kokuki", first.getSeriesName());
assertEquals("Juuni Kokki", first.getSeriesName());
assertEquals("Shadow of the Moon, The Sea of Shadow - Chapter 1", first.getTitle());
assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getAbsolute().toString());
assertEquals(null, first.getSeason());
assertEquals("2002-04-09", first.airdate().toString());
}

View File

@ -46,6 +46,7 @@ public class TVRageClientTest {
assertEquals("Chosen", chosen.getTitle());
assertEquals("22", chosen.getEpisode().toString());
assertEquals("7", chosen.getSeason().toString());
assertEquals("144", chosen.getAbsolute().toString());
assertEquals("2003-05-20", chosen.airdate().toString());
}
@ -62,6 +63,7 @@ public class TVRageClientTest {
assertEquals("Unaired Pilot", first.getTitle());
assertEquals("0", first.getEpisode().toString());
assertEquals("0", first.getSeason().toString());
assertEquals("0", first.getAbsolute().toString());
assertEquals(null, first.airdate());
}

View File

@ -66,6 +66,7 @@ public class TheTVDBClientTest {
assertEquals("Welcome to the Hellmouth (1)", first.getTitle());
assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getSeason().toString());
assertEquals("1", first.getAbsolute().toString());
assertEquals("1997-03-10", first.airdate().toString());
// check special episode
@ -74,6 +75,7 @@ public class TheTVDBClientTest {
assertEquals("Unaired Pilot", last.getTitle());
assertEquals("1", last.getSeason().toString());
assertEquals(null, last.getEpisode());
assertEquals("1", first.getAbsolute().toString());
assertEquals("1", last.getSpecial().toString());
assertEquals(null, last.airdate());
}
@ -91,6 +93,7 @@ public class TheTVDBClientTest {
assertEquals("Wax Lion", first.getTitle());
assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getSeason().toString());
assertEquals(null, first.getAbsolute()); // should be "1" but data has not yet been entered
assertEquals("2004-03-12", first.airdate().toString());
}