diff --git a/source/net/filebot/web/AnidbClient.java b/source/net/filebot/web/AnidbClient.java index 09fca336..5701e21a 100644 --- a/source/net/filebot/web/AnidbClient.java +++ b/source/net/filebot/web/AnidbClient.java @@ -144,6 +144,7 @@ public class AnidbClient extends AbstractEpisodeListProvider { int type = Integer.parseInt(getAttribute("type", epno)); if (type == 1 || type == 2) { + Integer id = Integer.parseInt(getAttribute("id", node)); SimpleDate airdate = SimpleDate.parse(getTextContent("airdate", node)); String title = selectString(".//title[@lang='" + locale.getLanguage() + "']", node); if (title.isEmpty()) { // English language fall-back @@ -151,9 +152,9 @@ public class AnidbClient extends AbstractEpisodeListProvider { } if (type == 1) { - episodes.add(new Episode(animeTitle, null, number, title, number, null, airdate, new SeriesInfo(seriesInfo))); // normal episode, no seasons for anime + episodes.add(new Episode(animeTitle, null, number, title, number, null, airdate, id, new SeriesInfo(seriesInfo))); // normal episode, no seasons for anime } else { - episodes.add(new Episode(animeTitle, null, null, title, null, number, airdate, new SeriesInfo(seriesInfo))); // special episode + episodes.add(new Episode(animeTitle, null, null, title, null, number, airdate, id, new SeriesInfo(seriesInfo))); // special episode } } } diff --git a/source/net/filebot/web/Episode.java b/source/net/filebot/web/Episode.java index 81fa57d6..79e3c0ee 100644 --- a/source/net/filebot/web/Episode.java +++ b/source/net/filebot/web/Episode.java @@ -5,10 +5,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.Set; public class Episode implements Serializable { + // base episode record protected String seriesName; protected Integer season; protected Integer episode; @@ -23,6 +25,9 @@ public class Episode implements Serializable { // episode airdate protected SimpleDate airdate; + // unique identifier + protected Integer id; + // extended series metadata protected SeriesInfo seriesInfo; @@ -31,14 +36,14 @@ public class Episode implements Serializable { } public Episode(Episode obj) { - this(obj.seriesName, obj.season, obj.episode, obj.title, obj.absolute, obj.special, obj.airdate, obj.seriesInfo); + this(obj.seriesName, obj.season, obj.episode, obj.title, obj.absolute, obj.special, obj.airdate, obj.id, obj.seriesInfo); } public Episode(String seriesName, Integer season, Integer episode, String title) { - this(seriesName, season, episode, title, null, null, null, null); + this(seriesName, season, episode, title, null, null, null, null, null); } - public Episode(String seriesName, Integer season, Integer episode, String title, Integer absolute, Integer special, SimpleDate airdate, SeriesInfo seriesInfo) { + public Episode(String seriesName, Integer season, Integer episode, String title, Integer absolute, Integer special, SimpleDate airdate, Integer id, SeriesInfo seriesInfo) { this.seriesName = seriesName; this.season = season; this.episode = episode; @@ -46,6 +51,7 @@ public class Episode implements Serializable { this.absolute = absolute; this.special = special; this.airdate = airdate == null ? null : airdate.clone(); + this.id = id; this.seriesInfo = seriesInfo == null ? null : seriesInfo.clone(); } @@ -77,6 +83,10 @@ public class Episode implements Serializable { return airdate; } + public Integer getId() { + return id; + } + public SeriesInfo getSeriesInfo() { return seriesInfo; } @@ -107,22 +117,22 @@ public class Episode implements Serializable { public boolean equals(Object obj) { if (obj instanceof Episode) { Episode other = (Episode) obj; - return equals(season, other.season) && equals(episode, other.episode) && equals(absolute, other.absolute) && equals(special, other.special) && equals(seriesName, other.seriesName) && equals(title, other.title); + + // check if database id matches + if (id != null && other.id != null) { + return id.equals(other.id) && Objects.equals(seriesInfo, other.seriesInfo); + } + + // check if episode record matches + return Objects.equals(season, other.season) && Objects.equals(episode, other.episode) && Objects.equals(absolute, other.absolute) && Objects.equals(special, other.special) && Objects.equals(seriesName, other.seriesName) && Objects.equals(title, other.title); } return false; } - private boolean equals(Object o1, Object o2) { - if (o1 == null || o2 == null) - return o1 == o2; - - return o1.equals(o2); - } - @Override public int hashCode() { - return Arrays.hashCode(new Object[] { season, episode, absolute, special, seriesName, title }); + return id != null ? id : Objects.hash(season, episode, absolute, special, seriesName, title); } @Override diff --git a/source/net/filebot/web/EpisodeFormat.java b/source/net/filebot/web/EpisodeFormat.java index fa77692b..6acbead2 100644 --- a/source/net/filebot/web/EpisodeFormat.java +++ b/source/net/filebot/web/EpisodeFormat.java @@ -163,7 +163,7 @@ public class EpisodeFormat extends Format { // did parse input pos.setIndex(source.length()); - return new Episode(name, season, episode, title, season == null ? episode : null, special, airdate, null); + return new Episode(name, season, episode, title, season == null ? episode : null, special, airdate, null, null); } // failed to parse input diff --git a/source/net/filebot/web/TMDbTVClient.java b/source/net/filebot/web/TMDbTVClient.java index 98f6d189..8aecf8bb 100644 --- a/source/net/filebot/web/TMDbTVClient.java +++ b/source/net/filebot/web/TMDbTVClient.java @@ -120,6 +120,7 @@ public class TMDbTVClient extends AbstractEpisodeListProvider { Object season = tmdb.request("tv/" + series.getId() + "/season/" + s, emptyMap(), locale, REQUEST_LIMIT); streamJsonObjects(season, "episodes").forEach(episode -> { + Integer id = getInteger(episode, "id"); Integer episodeNumber = getInteger(episode, "episode_number"); Integer seasonNumber = getInteger(episode, "season_number"); String episodeTitle = getString(episode, "name"); @@ -128,9 +129,9 @@ public class TMDbTVClient extends AbstractEpisodeListProvider { Integer absoluteNumber = episodes.size() + 1; if (s > 0) { - episodes.add(new Episode(series.getName(), seasonNumber, episodeNumber, episodeTitle, absoluteNumber, null, airdate, info)); + episodes.add(new Episode(series.getName(), seasonNumber, episodeNumber, episodeTitle, absoluteNumber, null, airdate, id, info)); } else { - specials.add(new Episode(series.getName(), null, null, episodeTitle, null, episodeNumber, airdate, info)); + specials.add(new Episode(series.getName(), null, null, episodeTitle, null, episodeNumber, airdate, id, info)); } }); } diff --git a/source/net/filebot/web/TVMazeClient.java b/source/net/filebot/web/TVMazeClient.java index 04b943aa..8d953e03 100644 --- a/source/net/filebot/web/TVMazeClient.java +++ b/source/net/filebot/web/TVMazeClient.java @@ -89,12 +89,13 @@ public class TVMazeClient extends AbstractEpisodeListProvider { Object response = request("shows/" + seriesInfo.getId() + "/episodes"); List episodes = streamJsonObjects(response).map(episode -> { - String episodeTitle = getString(episode, "name"); + Integer id = getInteger(episode, "id"); Integer seasonNumber = getInteger(episode, "season"); Integer episodeNumber = getInteger(episode, "number"); + String episodeTitle = getString(episode, "name"); SimpleDate airdate = getStringValue(episode, "airdate", SimpleDate::parse); - return new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeTitle, null, null, airdate, seriesInfo); + return new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeTitle, null, null, airdate, id, seriesInfo); }).collect(toList()); return new SeriesData(seriesInfo, episodes); diff --git a/source/net/filebot/web/TheTVDBClient.java b/source/net/filebot/web/TheTVDBClient.java index e1bedb4b..8400a03e 100644 --- a/source/net/filebot/web/TheTVDBClient.java +++ b/source/net/filebot/web/TheTVDBClient.java @@ -181,6 +181,7 @@ public class TheTVDBClient extends AbstractEpisodeListProvider implements Artwor String episodeName = getString(it, "episodeName"); Integer absoluteNumber = getInteger(it, "absoluteNumber"); SimpleDate airdate = getStringValue(it, "firstAired", SimpleDate::parse); + Integer id = getInteger(it, "id"); // default numbering Integer episodeNumber = getInteger(it, "airedEpisodeNumber"); @@ -203,10 +204,10 @@ public class TheTVDBClient extends AbstractEpisodeListProvider implements Artwor if (seasonNumber == null || seasonNumber > 0) { // handle as normal episode - episodes.add(new Episode(info.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, new SeriesInfo(info))); + episodes.add(new Episode(info.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, id, new SeriesInfo(info))); } else { // handle as special episode - specials.add(new Episode(info.getName(), null, null, episodeName, null, episodeNumber, airdate, new SeriesInfo(info))); + specials.add(new Episode(info.getName(), null, null, episodeName, null, episodeNumber, airdate, id, new SeriesInfo(info))); } }); } diff --git a/source/net/filebot/web/TheTVDBClientV1.java b/source/net/filebot/web/TheTVDBClientV1.java index be52ed01..478b0d89 100644 --- a/source/net/filebot/web/TheTVDBClientV1.java +++ b/source/net/filebot/web/TheTVDBClientV1.java @@ -148,6 +148,7 @@ public class TheTVDBClientV1 extends AbstractEpisodeListProvider implements Artw String episodeName = getTextContent("EpisodeName", node); Integer absoluteNumber = matchInteger(getTextContent("absolute_number", node)); SimpleDate airdate = SimpleDate.parse(getTextContent("FirstAired", node)); + Integer id = matchInteger(getTextContent("id", node)); // default numbering Integer episodeNumber = matchInteger(getTextContent("EpisodeNumber", node)); @@ -178,7 +179,7 @@ public class TheTVDBClientV1 extends AbstractEpisodeListProvider implements Artw // use given episode number as special number or count specials by ourselves Integer specialNumber = (episodeNumber != null) ? episodeNumber : filterBySeason(specials, seasonNumber).size() + 1; - specials.add(new Episode(seriesInfo.getName(), seasonNumber, null, episodeName, null, specialNumber, airdate, new SeriesInfo(seriesInfo))); + specials.add(new Episode(seriesInfo.getName(), seasonNumber, null, episodeName, null, specialNumber, airdate, id, new SeriesInfo(seriesInfo))); } else { // adjust for absolute numbering if possible if (sortOrder == SortOrder.Absolute) { @@ -189,7 +190,7 @@ public class TheTVDBClientV1 extends AbstractEpisodeListProvider implements Artw } // handle as normal episode - episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, new SeriesInfo(seriesInfo))); + episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, id, new SeriesInfo(seriesInfo))); } } diff --git a/test/net/filebot/similarity/EpisodeMetricsTest.java b/test/net/filebot/similarity/EpisodeMetricsTest.java index 450c9121..c08a7a34 100644 --- a/test/net/filebot/similarity/EpisodeMetricsTest.java +++ b/test/net/filebot/similarity/EpisodeMetricsTest.java @@ -57,8 +57,8 @@ public class EpisodeMetricsTest { @Test public void numericNumbers() { String fn = "SEED - 01 - [X 2.0]"; - Episode e1 = new Episode("SEED", null, 1, "Enraged Eyes", 1, null, new SimpleDate(2004, 10, 9), null); - Episode s1 = new Episode("SEED", null, null, "EDITED", null, 1, new SimpleDate(2005, 1, 29), null); + Episode e1 = new Episode("SEED", null, 1, "Enraged Eyes", 1, null, new SimpleDate(2004, 10, 9), null, null); + Episode s1 = new Episode("SEED", null, null, "EDITED", null, 1, new SimpleDate(2005, 1, 29), null, null); assertEquals(0.5, Numeric.getSimilarity(fn, e1), 0.01); assertEquals(0.5, Numeric.getSimilarity(fn, s1), 0.01); diff --git a/test/net/filebot/web/AnidbClientTest.java b/test/net/filebot/web/AnidbClientTest.java index 6c179ab8..790be64e 100644 --- a/test/net/filebot/web/AnidbClientTest.java +++ b/test/net/filebot/web/AnidbClientTest.java @@ -73,6 +73,7 @@ public class AnidbClientTest { assertEquals("1", first.getAbsolute().toString()); assertEquals(null, first.getSeason()); assertEquals("2004-04-07", first.getAirdate().toString()); + assertEquals("17843", first.getId().toString()); } @Test diff --git a/test/net/filebot/web/TMDbTVClientTest.java b/test/net/filebot/web/TMDbTVClientTest.java index a77a6211..1afa54f8 100644 --- a/test/net/filebot/web/TMDbTVClientTest.java +++ b/test/net/filebot/web/TMDbTVClientTest.java @@ -65,6 +65,7 @@ public class TMDbTVClientTest { assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getAbsolute().toString()); assertEquals("2004-03-12", first.getAirdate().toString()); + assertEquals("134989", first.getId().toString()); } } diff --git a/test/net/filebot/web/TVMazeClientTest.java b/test/net/filebot/web/TVMazeClientTest.java index 9d1678c8..5507f014 100644 --- a/test/net/filebot/web/TVMazeClientTest.java +++ b/test/net/filebot/web/TVMazeClientTest.java @@ -42,6 +42,7 @@ public class TVMazeClientTest { assertEquals("7", chosen.getSeason().toString()); assertEquals(null, chosen.getAbsolute()); assertEquals("2003-05-20", chosen.getAirdate().toString()); + assertEquals("40175", chosen.getId().toString()); } @Test @@ -58,6 +59,7 @@ public class TVMazeClientTest { assertEquals("1", first.getSeason().toString()); assertEquals(null, first.getAbsolute()); assertEquals("1997-03-10", first.getAirdate().toString()); + assertEquals("40033", first.getId().toString()); } @Test diff --git a/test/net/filebot/web/TheTVDBClientTest.java b/test/net/filebot/web/TheTVDBClientTest.java index a852f3be..4397739a 100644 --- a/test/net/filebot/web/TheTVDBClientTest.java +++ b/test/net/filebot/web/TheTVDBClientTest.java @@ -77,6 +77,7 @@ public class TheTVDBClientTest { assertEquals("1", first.getSeason().toString()); assertEquals(null, first.getAbsolute()); // should be "1" but data has not yet been entered assertEquals("2004-03-12", first.getAirdate().toString()); + assertEquals("296337", first.getId().toString()); } @Test @@ -139,10 +140,10 @@ public class TheTVDBClientTest { public void getArtwork() throws Exception { Artwork i = db.getArtwork(buffy.getId(), "fanart", Locale.ENGLISH).get(0); - assertEquals("[fanart, 1920x1080]", i.getTags().toString()); - assertEquals("http://thetvdb.com/banners/fanart/original/70327-7.jpg", i.getUrl().toString()); - assertTrue(i.matches("fanart", "1920x1080")); - assertFalse(i.matches("fanart", "1920x1080", "1")); + assertEquals("[fanart, 1280x720]", i.getTags().toString()); + assertEquals("http://thetvdb.com/banners/fanart/original/70327-23.jpg", i.getUrl().toString()); + assertTrue(i.matches("fanart", "1280x720")); + assertFalse(i.matches("fanart", "1280x720", "1")); assertEquals(8.0, i.getRating(), 1.0); } @@ -157,7 +158,7 @@ public class TheTVDBClientTest { Person p = db.getActors(firefly.getId(), Locale.ENGLISH).get(0); assertEquals("Alan Tudyk", p.getName()); assertEquals("Hoban 'Wash' Washburne", p.getCharacter()); - assertEquals(null, p.getJob()); + assertEquals("Actor", p.getJob()); assertEquals(null, p.getDepartment()); assertEquals("0", p.getOrder().toString()); assertEquals("http://thetvdb.com/banners/actors/68409.jpg", p.getImage().toString()); diff --git a/test/net/filebot/web/TheTVDBClientV1Test.java b/test/net/filebot/web/TheTVDBClientV1Test.java index 273e251b..e3bdba7f 100644 --- a/test/net/filebot/web/TheTVDBClientV1Test.java +++ b/test/net/filebot/web/TheTVDBClientV1Test.java @@ -79,6 +79,7 @@ public class TheTVDBClientV1Test { assertEquals("1", first.getSeason().toString()); assertEquals(null, first.getAbsolute()); // should be "1" but data has not yet been entered assertEquals("2004-03-12", first.getAirdate().toString()); + assertEquals("296337", first.getId().toString()); } @Test @@ -93,6 +94,7 @@ public class TheTVDBClientV1Test { assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getAbsolute().toString()); assertEquals("2002-12-20", first.getAirdate().toString()); + assertEquals("297999", first.getId().toString()); } public void getEpisodeListLink() {