* added support for airdate in episode naming scheme (new binding "air")

* parse airdate in all episode list providers (TVRage, AniDB, TV.com, IMDb, TheTVDB)
This commit is contained in:
Reinhard Pointner 2010-10-23 12:47:43 +00:00
parent 8364015504
commit 5db098e95a
15 changed files with 158 additions and 39 deletions

View File

@ -19,6 +19,7 @@ import net.sf.ehcache.Element;
import net.sourceforge.filebot.hash.HashType; import net.sourceforge.filebot.hash.HashType;
import net.sourceforge.filebot.mediainfo.MediaInfo; import net.sourceforge.filebot.mediainfo.MediaInfo;
import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind; import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
import net.sourceforge.filebot.web.Date;
import net.sourceforge.filebot.web.Episode; import net.sourceforge.filebot.web.Episode;
import net.sourceforge.tuned.FileUtilities; import net.sourceforge.tuned.FileUtilities;
@ -69,6 +70,12 @@ public class EpisodeBindingBean {
} }
@Define("air")
public Date airdate() {
return episode.airdate();
}
@Define("vc") @Define("vc")
public String getVideoCodec() { public String getVideoCodec() {
// e.g. XviD, x264, DivX 5, MPEG-4 Visual, AVC, etc. // e.g. XviD, x264, DivX 5, MPEG-4 Visual, AVC, etc.

View File

@ -54,6 +54,7 @@ import net.sourceforge.filebot.ResourceManager;
import net.sourceforge.filebot.Settings; import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.format.EpisodeBindingBean; import net.sourceforge.filebot.format.EpisodeBindingBean;
import net.sourceforge.filebot.format.ExpressionFormat; import net.sourceforge.filebot.format.ExpressionFormat;
import net.sourceforge.filebot.web.Date;
import net.sourceforge.filebot.web.Episode; import net.sourceforge.filebot.web.Episode;
import net.sourceforge.filebot.web.EpisodeFormat; import net.sourceforge.filebot.web.EpisodeFormat;
import net.sourceforge.tuned.DefaultThreadFactory; import net.sourceforge.tuned.DefaultThreadFactory;
@ -290,7 +291,7 @@ class EpisodeFormatDialog extends JDialog {
episode = EpisodeFormat.getInstance().parseObject(persistentSampleEpisode.getValue()); episode = EpisodeFormat.getInstance().parseObject(persistentSampleEpisode.getValue());
} catch (Exception e) { } catch (Exception e) {
// default sample // default sample
episode = new Episode("Dark Angel", 3, 1, "Labyrinth"); episode = new Episode("Dark Angel", "3", "1", "Labyrinth", null, new Date(2009, 6, 1));
} }
// restore media file // restore media file

View File

@ -146,9 +146,10 @@ public class AnidbClient implements EpisodeListProvider {
// ignore special episodes // ignore special episodes
if (number != null && number.matches("\\d+")) { if (number != null && number.matches("\\d+")) {
String title = selectString(".//title[@lang='en']", node); String title = selectString(".//title[@lang='en']", node);
String airdate = selectString(".//date/@rel", node);
// no seasons for anime // no seasons for anime
episodes.add(new Episode(animeTitle, null, number, title)); episodes.add(new Episode(animeTitle, null, number, title, null, Date.parse(airdate, "yyyy-MM-dd")));
} }
} }

View File

@ -0,0 +1,77 @@
package net.sourceforge.filebot.web;
import static java.util.Calendar.*;
import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Date implements Serializable {
private int year;
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;
}
@Override
public String toString() {
return String.format("%04d-%02d-%02d", year, month, day);
}
public String format(String pattern) {
return new SimpleDateFormat(pattern).format(new GregorianCalendar(year, month, day).getTime());
}
public static Date parse(String string, String pattern) {
SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.ROOT);
formatter.setLenient(false); // enable strict mode (e.g. fail on invalid dates like 0000-00-00)
try {
Calendar date = new GregorianCalendar(Locale.ROOT);
date.setTime(formatter.parse(string));
return new Date(date.get(YEAR), date.get(MONTH) + 1, date.get(DAY_OF_MONTH));
} catch (ParseException e) {
// no result if date is invalid
Logger.getLogger(Date.class.getName()).log(Level.WARNING, e.getMessage());
return null;
}
}
}

View File

@ -12,30 +12,36 @@ public class Episode implements Serializable {
private String season; private String season;
private String episode; private String episode;
private String title; private String title;
// special number
private String special; private String special;
// episode airdate
private Date airdate;
protected Episode() { protected Episode() {
// used by serializer // used by serializer
} }
public Episode(String seriesName, int season, int episode, String title) {
this(seriesName, String.valueOf(season), String.valueOf(episode), title, null);
}
public Episode(String seriesName, String season, String episode, String title) { public Episode(String seriesName, String season, String episode, String title) {
this(seriesName, season, episode, title, null); this(seriesName, season, episode, title, null, null);
} }
public Episode(String seriesName, String season, String episode, String title, String special) { public Episode(String seriesName, String season, String episode, String title, String special, Date airdate) {
this.seriesName = seriesName; this.seriesName = seriesName;
this.season = season; this.season = season;
this.episode = episode; this.episode = episode;
this.title = title; this.title = title;
this.special = special; this.special = special;
this.airdate = airdate;
}
public String getSeriesName() {
return seriesName;
} }
@ -67,6 +73,11 @@ public class Episode implements Serializable {
} }
public String getTitle() {
return title;
}
public String getSpecial() { public String getSpecial() {
return special; return special;
} }
@ -81,13 +92,8 @@ public class Episode implements Serializable {
} }
public String getSeriesName() { public Date airdate() {
return seriesName; return airdate;
}
public String getTitle() {
return title;
} }

View File

@ -97,13 +97,16 @@ public class IMDbClient implements EpisodeListProvider {
List<Episode> episodes = new ArrayList<Episode>(nodes.size()); List<Episode> episodes = new ArrayList<Episode>(nodes.size());
for (Node node : nodes) { for (Node node : nodes) {
String title = node.getTextContent().trim(); String title = getTextContent(node);
Scanner numberScanner = new Scanner(node.getPreviousSibling().getTextContent()).useDelimiter("\\D+"); Scanner numberScanner = new Scanner(node.getPreviousSibling().getTextContent()).useDelimiter("\\D+");
String season = numberScanner.next(); String season = numberScanner.next();
String episode = numberScanner.next(); String episode = numberScanner.next();
episodes.add(new Episode(seriesName, season, episode, title)); // 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")));
} }
return episodes; return episodes;

View File

@ -148,8 +148,9 @@ public class TVDotComClient implements EpisodeListProvider {
List<Node> nodes = selectNodes("id('episode_guide_list')//*[@class='info']", dom); List<Node> nodes = selectNodes("id('episode_guide_list')//*[@class='info']", dom);
Pattern episodePattern = Pattern.compile("Season (\\d+). Episode (\\d+)"); Pattern episodePattern = Pattern.compile("Season.(\\d+).+Episode.(\\d+)");
Pattern specialPattern = Pattern.compile("Special. Season (\\d+)"); Pattern specialPattern = Pattern.compile("Special..Season.(\\d+)");
Pattern airdatePattern = Pattern.compile("(\\d{1,2}).(\\d{1,2}).(\\d{4})");
List<Episode> episodes = new ArrayList<Episode>(nodes.size()); List<Episode> episodes = new ArrayList<Episode>(nodes.size());
@ -159,9 +160,11 @@ public class TVDotComClient implements EpisodeListProvider {
String season = null; String season = null;
String episode = null; String episode = null;
Date airdate = null;
Matcher matcher; Matcher matcher;
// try to match episode information
if ((matcher = episodePattern.matcher(meta)).find()) { if ((matcher = episodePattern.matcher(meta)).find()) {
// matches episode // matches episode
season = matcher.group(1); season = matcher.group(1);
@ -170,12 +173,17 @@ public class TVDotComClient implements EpisodeListProvider {
// matches special // matches special
season = matcher.group(1); season = matcher.group(1);
episode = "Special"; episode = "Special";
} else {
// no episode match
continue;
} }
episodes.add(new Episode(searchResult.getName(), season, episode, title)); // try to match airdate information
if ((matcher = airdatePattern.matcher(meta)).find()) {
airdate = Date.parse(matcher.group(), "MM/dd/yyyy"); // e.g. 5/20/2003
}
// 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 are listed in reverse order // episodes are listed in reverse order

View File

@ -87,16 +87,17 @@ public class TVRageClient implements EpisodeListProvider {
String title = getTextContent("title", node); String title = getTextContent("title", node);
String episodeNumber = getTextContent("seasonnum", node); String episodeNumber = getTextContent("seasonnum", node);
String seasonNumber = getAttribute("no", node.getParentNode()); String seasonNumber = getAttribute("no", node.getParentNode());
Date airdate = Date.parse(getTextContent("airdate", node), "yyyy-MM-dd");
// check if we have season and episode number, if not it must be a special episode // check if we have season and episode number, if not it must be a special episode
if (episodeNumber == null || seasonNumber == null) { if (episodeNumber == null || seasonNumber == null) {
// handle as special episode // handle as special episode
seasonNumber = getTextContent("season", node); seasonNumber = getTextContent("season", node);
int specialNumber = filterBySeason(specials, Integer.parseInt(seasonNumber)).size() + 1; int specialNumber = filterBySeason(specials, Integer.parseInt(seasonNumber)).size() + 1;
specials.add(new Episode(seriesName, seasonNumber, "Special " + specialNumber, title, Integer.toString(specialNumber))); specials.add(new Episode(seriesName, seasonNumber, "Special " + specialNumber, title, Integer.toString(specialNumber), airdate));
} else { } else {
// handle as normal episode // handle as normal episode
episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, title)); episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, title, null, airdate));
} }
} }

View File

@ -135,6 +135,7 @@ public class TheTVDBClient implements EpisodeListProvider {
String episodeName = getTextContent("EpisodeName", node); String episodeName = getTextContent("EpisodeName", node);
String episodeNumber = getTextContent("EpisodeNumber", node); String episodeNumber = getTextContent("EpisodeNumber", node);
String seasonNumber = getTextContent("SeasonNumber", node); String seasonNumber = getTextContent("SeasonNumber", node);
Date airdate = Date.parse(getTextContent("FirstAired", node), "yyyy-MM-dd");
if (seasonNumber.equals("0")) { if (seasonNumber.equals("0")) {
// handle as special episode // handle as special episode
@ -145,10 +146,10 @@ public class TheTVDBClient implements EpisodeListProvider {
} }
int specialNumber = filterBySeason(specials, Integer.parseInt(seasonNumber)).size() + 1; int specialNumber = filterBySeason(specials, Integer.parseInt(seasonNumber)).size() + 1;
specials.add(new Episode(seriesName, seasonNumber, "Special " + specialNumber, episodeName, Integer.toString(specialNumber))); specials.add(new Episode(seriesName, seasonNumber, "Special " + specialNumber, episodeName, Integer.toString(specialNumber), airdate));
} else { } else {
// handle as normal episode // handle as normal episode
episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, episodeName)); episodes.add(new Episode(seriesName, seasonNumber, episodeNumber, episodeName, null, airdate));
} }
if (episodeNumber.equals("1")) { if (episodeNumber.equals("1")) {

View File

@ -85,6 +85,7 @@ public class AnidbClientTest {
assertEquals("Herr Dr. Tenma", first.getTitle()); assertEquals("Herr Dr. Tenma", first.getTitle());
assertEquals("1", first.getEpisode()); assertEquals("1", first.getEpisode());
assertEquals(null, first.getSeason()); assertEquals(null, first.getSeason());
assertEquals("2004-04-07", first.airdate().toString());
} }
@ -100,6 +101,7 @@ public class AnidbClientTest {
assertEquals("Shadow of the Moon, The Sea of Shadow - Chapter 1", first.getTitle()); assertEquals("Shadow of the Moon, The Sea of Shadow - Chapter 1", first.getTitle());
assertEquals("1", first.getEpisode()); assertEquals("1", first.getEpisode());
assertEquals(null, first.getSeason()); assertEquals(null, first.getSeason());
assertEquals("2002-04-09", first.airdate().toString());
} }

View File

@ -74,6 +74,7 @@ public class IMDbClientTest {
assertEquals("Unaired Pilot", first.getTitle()); assertEquals("Unaired Pilot", first.getTitle());
assertEquals("0", first.getEpisode()); assertEquals("0", first.getEpisode());
assertEquals("1", first.getSeason()); assertEquals("1", first.getSeason());
assertEquals(null, first.airdate());
Episode last = list.get(144); Episode last = list.get(144);
@ -81,6 +82,7 @@ public class IMDbClientTest {
assertEquals("Chosen", last.getTitle()); assertEquals("Chosen", last.getTitle());
assertEquals("22", last.getEpisode()); assertEquals("22", last.getEpisode());
assertEquals("7", last.getSeason()); assertEquals("7", last.getSeason());
assertEquals("2003-05-20", last.airdate().toString());
} }
@ -92,7 +94,7 @@ public class IMDbClientTest {
Episode first = list.get(0); Episode first = list.get(0);
assertEquals("Mushi-Shi", first.getSeriesName()); assertEquals("Mushishi", first.getSeriesName());
assertEquals("Midori no za", first.getTitle()); assertEquals("Midori no za", first.getTitle());
assertEquals("1", first.getEpisode()); assertEquals("1", first.getEpisode());
assertEquals("1", first.getSeason()); assertEquals("1", first.getSeason());

View File

@ -58,6 +58,7 @@ public class TVDotComClientTest {
assertEquals("Chosen", chosen.getTitle()); assertEquals("Chosen", chosen.getTitle());
assertEquals("22", chosen.getEpisode()); assertEquals("22", chosen.getEpisode());
assertEquals("7", chosen.getSeason()); assertEquals("7", chosen.getSeason());
assertEquals("2003-05-20", chosen.airdate().toString());
} }
@ -74,6 +75,7 @@ public class TVDotComClientTest {
assertEquals("Welcome to the Hellmouth (1)", first.getTitle()); assertEquals("Welcome to the Hellmouth (1)", first.getTitle());
assertEquals("1", first.getEpisode()); assertEquals("1", first.getEpisode());
assertEquals("1", first.getSeason()); assertEquals("1", first.getSeason());
assertEquals("1997-03-10", first.airdate().toString());
} }
@ -90,6 +92,7 @@ public class TVDotComClientTest {
assertEquals("Jaynestown", fourth.getTitle()); assertEquals("Jaynestown", fourth.getTitle());
assertEquals("4", fourth.getEpisode()); assertEquals("4", fourth.getEpisode());
assertEquals("1", fourth.getSeason()); assertEquals("1", fourth.getSeason());
assertEquals("2002-10-18", fourth.airdate().toString());
} }
@ -113,6 +116,7 @@ public class TVDotComClientTest {
assertEquals("Exposé", episode.getTitle()); assertEquals("Exposé", episode.getTitle());
assertEquals("14", episode.getEpisode()); assertEquals("14", episode.getEpisode());
assertEquals("3", episode.getSeason()); assertEquals("3", episode.getSeason());
assertEquals("2007-03-28", episode.airdate().toString());
} }

View File

@ -6,10 +6,10 @@ import static org.junit.Assert.*;
import java.util.List; import java.util.List;
import net.sourceforge.filebot.web.TVRageClient.TVRageSearchResult;
import org.junit.Test; import org.junit.Test;
import net.sourceforge.filebot.web.TVRageClient.TVRageSearchResult;
public class TVRageClientTest { public class TVRageClientTest {
@ -18,7 +18,7 @@ public class TVRageClientTest {
*/ */
private static TVRageSearchResult buffySearchResult = new TVRageSearchResult("Buffy the Vampire Slayer", 2930, "http://www.tvrage.com/Buffy_The_Vampire_Slayer"); private static TVRageSearchResult buffySearchResult = new TVRageSearchResult("Buffy the Vampire Slayer", 2930, "http://www.tvrage.com/Buffy_The_Vampire_Slayer");
@Test @Test
public void search() throws Exception { public void search() throws Exception {
List<SearchResult> results = tvrage.search("Buffy"); List<SearchResult> results = tvrage.search("Buffy");
@ -30,9 +30,10 @@ public class TVRageClientTest {
assertEquals(buffySearchResult.getLink(), result.getLink()); assertEquals(buffySearchResult.getLink(), result.getLink());
} }
private TVRageClient tvrage = new TVRageClient(); private TVRageClient tvrage = new TVRageClient();
@Test @Test
public void getEpisodeList() throws Exception { public void getEpisodeList() throws Exception {
List<Episode> list = tvrage.getEpisodeList(buffySearchResult, 7); List<Episode> list = tvrage.getEpisodeList(buffySearchResult, 7);
@ -45,6 +46,7 @@ public class TVRageClientTest {
assertEquals("Chosen", chosen.getTitle()); assertEquals("Chosen", chosen.getTitle());
assertEquals("22", chosen.getEpisode()); assertEquals("22", chosen.getEpisode());
assertEquals("7", chosen.getSeason()); assertEquals("7", chosen.getSeason());
assertEquals("2003-05-20", chosen.airdate().toString());
} }
@ -60,6 +62,7 @@ public class TVRageClientTest {
assertEquals("Unaired Pilot", first.getTitle()); assertEquals("Unaired Pilot", first.getTitle());
assertEquals("00", first.getEpisode()); assertEquals("00", first.getEpisode());
assertEquals("0", first.getSeason()); assertEquals("0", first.getSeason());
assertEquals(null, first.airdate());
} }

View File

@ -66,6 +66,7 @@ public class TheTVDBClientTest {
assertEquals("Welcome to the Hellmouth (1)", first.getTitle()); assertEquals("Welcome to the Hellmouth (1)", first.getTitle());
assertEquals("1", first.getEpisode()); assertEquals("1", first.getEpisode());
assertEquals("1", first.getSeason()); assertEquals("1", first.getSeason());
assertEquals("1997-03-10", first.airdate().toString());
// check special episode // check special episode
Episode last = list.get(list.size() - 1); Episode last = list.get(list.size() - 1);
@ -73,6 +74,7 @@ public class TheTVDBClientTest {
assertEquals("Unaired Pilot", last.getTitle()); assertEquals("Unaired Pilot", last.getTitle());
assertEquals("Special 1", last.getEpisode()); assertEquals("Special 1", last.getEpisode());
assertEquals("1", last.getSeason()); assertEquals("1", last.getSeason());
assertEquals(null, last.airdate());
} }
@ -82,12 +84,13 @@ public class TheTVDBClientTest {
assertEquals(13, list.size()); assertEquals(13, list.size());
Episode chosen = list.get(0); Episode first = list.get(0);
assertEquals("Wonderfalls", chosen.getSeriesName()); assertEquals("Wonderfalls", first.getSeriesName());
assertEquals("Wax Lion", chosen.getTitle()); assertEquals("Wax Lion", first.getTitle());
assertEquals("1", chosen.getEpisode()); assertEquals("1", first.getEpisode());
assertEquals("1", chosen.getSeason()); assertEquals("1", first.getSeason());
assertEquals("2004-03-12", first.airdate().toString());
} }

View File

@ -168,7 +168,7 @@ public class PreferencesMapTest {
public void serializableAdapter() { public void serializableAdapter() {
Map<String, Episode> map = PreferencesMap.map(temp, new SerializableAdapter<Episode>()); Map<String, Episode> map = PreferencesMap.map(temp, new SerializableAdapter<Episode>());
Episode episode = new Episode("8 Simple Rules", 1, 1, "Pilot"); Episode episode = new Episode("8 Simple Rules", "1", "1", "Pilot", null, null);
map.put("episode", episode); map.put("episode", episode);