From 828dd5f5adccfe23e209f781d75592faaec5badd Mon Sep 17 00:00:00 2001 From: Scott Rice Date: Mon, 21 Apr 2014 17:50:43 -0500 Subject: [PATCH] Adds Anime-specific searching and Fanzub support Splits searching in the same way as a Daily search, each indexer has a method to search specifically for anime. Fanzub support was also added, with its own indexer and parser classes. --- .../Definitions/AnimeEpisodeSearchCriteria.cs | 14 ++++ .../IndexerSearch/NzbSearchService.cs | 15 ++++ src/NzbDrone.Core/Indexers/Fanzub/Fanzub.cs | 75 +++++++++++++++++++ .../Indexers/Fanzub/FanzubParser.cs | 31 ++++++++ src/NzbDrone.Core/Indexers/IIndexer.cs | 1 + src/NzbDrone.Core/Indexers/IndexerBase.cs | 1 + .../Indexers/IndexerFetchService.cs | 12 +++ src/NzbDrone.Core/Indexers/Newznab/Newznab.cs | 6 ++ .../Indexers/Omgwtfnzbs/Omgwtfnzbs.cs | 6 ++ src/NzbDrone.Core/Indexers/Wombles/Wombles.cs | 5 ++ src/NzbDrone.Core/NzbDrone.Core.csproj | 4 + src/NzbDrone/NzbDrone.csproj | 4 +- 12 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs create mode 100644 src/NzbDrone.Core/Indexers/Fanzub/Fanzub.cs create mode 100644 src/NzbDrone.Core/Indexers/Fanzub/FanzubParser.cs diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs new file mode 100644 index 000000000..7e1c57bf4 --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs @@ -0,0 +1,14 @@ +using System; + +namespace NzbDrone.Core.IndexerSearch.Definitions +{ + public class AnimeEpisodeSearchCriteria : SearchCriteriaBase + { + public int AbsoluteEpisodeNumber { get; set; } + + public override string ToString() + { + return string.Format("[{0} : {1:00}]", SceneTitle, AbsoluteEpisodeNumber); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index 1b71323e6..97206d1f0 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -70,6 +70,10 @@ namespace NzbDrone.Core.IndexerSearch return SearchDaily(series, episode); } + if (series.SeriesType == SeriesTypes.Anime) + { + return SearchAnime(series, episode); + } if (episode.SeasonNumber == 0) { @@ -116,6 +120,17 @@ namespace NzbDrone.Core.IndexerSearch return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec); } + private List SearchAnime(Series series, Episode episode) + { + var searchSpec = Get(series, new List { episode }); + // TODO: Get the scene title from TheXEM + searchSpec.SceneTitle = series.Title; + // TODO: Calculate the Absolute Episode Number on the fly (if I have to) + searchSpec.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber.GetValueOrDefault(0); + + return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec); + } + private List SearchSpecial(Series series, List episodes) { var searchSpec = Get(series, episodes); diff --git a/src/NzbDrone.Core/Indexers/Fanzub/Fanzub.cs b/src/NzbDrone.Core/Indexers/Fanzub/Fanzub.cs new file mode 100644 index 000000000..2b914ef49 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Fanzub/Fanzub.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.Indexers.Fanzub +{ + public class Fanzub : IndexerBase + { + public override DownloadProtocol Protocol + { + get + { + return DownloadProtocol.Usenet; + } + } + + public override bool SupportsPaging + { + get + { + return false; + } + } + + public override bool SupportsSearching + { + get + { + return true; + } + } + + public override IParseFeed Parser + { + get + { + return new FanzubParser(); + } + } + + public override IEnumerable RecentFeed + { + get + { + yield return "http://fanzub.com/rss/?cat=anime"; + } + } + + public override IEnumerable GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber) + { + return new List(); + } + + public override IEnumerable GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset) + { + return new List(); + } + + public override IEnumerable GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date) + { + return new List(); + } + + public override IEnumerable GetAnimeEpisodeSearchUrls(string seriesTitle, int tvRageId, int absoluteEpisodeNumber) + { + return RecentFeed.Select(url => String.Format("{0}&q={1}%20{2}", url, seriesTitle, absoluteEpisodeNumber)); + } + + public override IEnumerable GetSearchUrls(string query, int offset) + { + return new List(); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Fanzub/FanzubParser.cs b/src/NzbDrone.Core/Indexers/Fanzub/FanzubParser.cs new file mode 100644 index 000000000..fe3229ca8 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Fanzub/FanzubParser.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using System.Linq; + +namespace NzbDrone.Core.Indexers.Fanzub +{ + public class FanzubParser : RssParserBase + { + protected override string GetNzbInfoUrl(XElement item) + { + IEnumerable matches = item.DescendantsAndSelf("link"); + if (matches.Any()) + { + return matches.First().Value; + } + return String.Empty; + } + + protected override long GetSize(XElement item) + { + IEnumerable matches = item.DescendantsAndSelf("enclosure"); + if (matches.Any()) + { + XElement enclosureElement = matches.First(); + return Convert.ToInt64(enclosureElement.Attribute("length").Value); + } + return 0; + } + } +} diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index fd70a2473..cc13c9b62 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.Indexers IEnumerable RecentFeed { get; } IEnumerable GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber); IEnumerable GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date); + IEnumerable GetAnimeEpisodeSearchUrls(string seriesTitle, int tvRageId, int absoluteEpisodeNumber); IEnumerable GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset); IEnumerable GetSearchUrls(string query, int offset = 0); } diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index bb73432c6..ac52df408 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -52,6 +52,7 @@ namespace NzbDrone.Core.Indexers public abstract IEnumerable RecentFeed { get; } public abstract IEnumerable GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber); public abstract IEnumerable GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date); + public abstract IEnumerable GetAnimeEpisodeSearchUrls(string seriesTitle, int tvRageId, int absoluteEpisodeNumber); public abstract IEnumerable GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset); public abstract IEnumerable GetSearchUrls(string query, int offset); diff --git a/src/NzbDrone.Core/Indexers/IndexerFetchService.cs b/src/NzbDrone.Core/Indexers/IndexerFetchService.cs index 154c160a0..fa0a8b271 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFetchService.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFetchService.cs @@ -18,6 +18,7 @@ namespace NzbDrone.Core.Indexers IList Fetch(IIndexer indexer, SeasonSearchCriteria searchCriteria); IList Fetch(IIndexer indexer, SingleEpisodeSearchCriteria searchCriteria); IList Fetch(IIndexer indexer, DailyEpisodeSearchCriteria searchCriteria); + IList Fetch(IIndexer indexer, AnimeEpisodeSearchCriteria searchCriteria); IList Fetch(IIndexer indexer, SpecialEpisodeSearchCriteria searchCriteria); } @@ -93,6 +94,17 @@ namespace NzbDrone.Core.Indexers return result; } + public IList Fetch(IIndexer indexer, AnimeEpisodeSearchCriteria searchCriteria) + { + _logger.Debug("Searching for {0}", searchCriteria); + + var searchUrls = indexer.GetAnimeEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.Series.TvRageId, searchCriteria.AbsoluteEpisodeNumber); + var result = Fetch(indexer, searchUrls); + _logger.Info("Finished searching {0} for {1}. Found {2}", indexer, searchCriteria, result.Count); + + return result; + } + public IList Fetch(IIndexer indexer, SpecialEpisodeSearchCriteria searchCriteria) { var queryUrls = new List(); diff --git a/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs index 9adcd88aa..41570f5b6 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs @@ -125,6 +125,12 @@ namespace NzbDrone.Core.Indexers.Newznab return RecentFeed.Select(url => String.Format("{0}&limit=100&q={1}&season={2:yyyy}&ep={2:MM}/{2:dd}", url, NewsnabifyTitle(seriesTitle), date)).ToList(); } + public override IEnumerable GetAnimeEpisodeSearchUrls(string seriesTitle, int tvRageId, int absoluteEpisodeNumber) + { + // TODO: Implement + return new List(); + } + public override IEnumerable GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset) { if (tvRageId > 0) diff --git a/src/NzbDrone.Core/Indexers/Omgwtfnzbs/Omgwtfnzbs.cs b/src/NzbDrone.Core/Indexers/Omgwtfnzbs/Omgwtfnzbs.cs index 6978213f8..277f70dbb 100644 --- a/src/NzbDrone.Core/Indexers/Omgwtfnzbs/Omgwtfnzbs.cs +++ b/src/NzbDrone.Core/Indexers/Omgwtfnzbs/Omgwtfnzbs.cs @@ -48,6 +48,12 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs return searchUrls; } + public override IEnumerable GetAnimeEpisodeSearchUrls(string seriesTitle, int tvRageId, int absoluteEpisodeNumber) + { + // TODO: Implement + return new List(); + } + public override IEnumerable GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset) { var searchUrls = new List(); diff --git a/src/NzbDrone.Core/Indexers/Wombles/Wombles.cs b/src/NzbDrone.Core/Indexers/Wombles/Wombles.cs index 8565ef9b9..82fa0bcbd 100644 --- a/src/NzbDrone.Core/Indexers/Wombles/Wombles.cs +++ b/src/NzbDrone.Core/Indexers/Wombles/Wombles.cs @@ -37,6 +37,11 @@ namespace NzbDrone.Core.Indexers.Wombles return new List(); } + public override IEnumerable GetAnimeEpisodeSearchUrls(string seriesTitle, int tvRageId, int absoluteEpisodeNumber) + { + return new List(); + } + public override IEnumerable GetSearchUrls(string query, int offset) { return new List(); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 97f8093a6..14ce01160 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -311,6 +311,7 @@ + @@ -323,6 +324,9 @@ + + + diff --git a/src/NzbDrone/NzbDrone.csproj b/src/NzbDrone/NzbDrone.csproj index ef38699aa..5437239ca 100644 --- a/src/NzbDrone/NzbDrone.csproj +++ b/src/NzbDrone/NzbDrone.csproj @@ -15,6 +15,8 @@ false + ..\ + true publish\ true Disk @@ -29,8 +31,6 @@ 1.0.0.%2a false true - ..\ - true x86