@ -9,144 +9,244 @@ namespace NzbDrone.Core.Indexers.Newznab
{
{
public class NewznabRequestGenerator : IIndexerRequestGenerator
public class NewznabRequestGenerator : IIndexerRequestGenerator
{
{
public Int32 MaxPages { get ; set ; }
private readonly INewznabCapabilitiesProvider _capabilitiesProvider ;
public Int32 PageSize { get ; set ; }
public int MaxPages { get ; set ; }
public int PageSize { get ; set ; }
public NewznabSettings Settings { get ; set ; }
public NewznabSettings Settings { get ; set ; }
public NewznabRequestGenerator ( )
public NewznabRequestGenerator ( INewznabCapabilitiesProvider capabilitiesProvider )
{
{
_capabilitiesProvider = capabilitiesProvider ;
MaxPages = 30 ;
MaxPages = 30 ;
PageSize = 100 ;
PageSize = 100 ;
}
}
p ublic virtual IList < IEnumerable < IndexerRequest > > GetRecentRequests ( )
p rivate bool SupportsSearch
{
{
var pageableRequests = new List < IEnumerable < IndexerRequest > > ( ) ;
get
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories . Concat ( Settings . AnimeCategories ) , "tvsearch" , "" ) ) ;
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
return pageableRequests ;
return capabilities . SupportedSearchParameters ! = null & &
capabilities . SupportedSearchParameters . Contains ( "q" ) ;
}
}
}
p ublic virtual IList < IEnumerable < IndexerRequest > > GetSearchRequests ( SingleEpisodeSearchCriteria searchCriteria )
p rivate bool SupportsTvSearch
{
{
var pageableRequests = new List < IEnumerable < IndexerRequest > > ( ) ;
get
if ( searchCriteria . Series . TvRageId > 0 )
{
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
String . Format ( "&rid={0}&season={1}&ep={2}" ,
searchCriteria . Series . TvRageId ,
return capabilities . SupportedTvSearchParameters ! = null & &
searchCriteria . SeasonNumber ,
capabilities . SupportedTvSearchParameters . Contains ( "q" ) & &
searchCriteria . EpisodeNumber ) ) ) ;
capabilities . SupportedTvSearchParameters . Contains ( "season" ) & &
capabilities . SupportedTvSearchParameters . Contains ( "ep" ) ;
}
}
else
}
private bool SupportsTvdbSearch
{
get
{
{
foreach ( var queryTitle in searchCriteria . QueryTitles )
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
return capabilities . SupportedTvSearchParameters ! = null & &
String . Format ( "&q={0}&season={1}&ep={2}" ,
capabilities . SupportedTvSearchParameters . Contains ( "tvdbid" ) & &
NewsnabifyTitle ( queryTitle ) ,
capabilities . SupportedTvSearchParameters . Contains ( "season" ) & &
searchCriteria . SeasonNumber ,
capabilities . SupportedTvSearchParameters . Contains ( "ep" ) ;
searchCriteria . EpisodeNumber ) ) ) ;
}
}
}
}
return pageableRequests ;
private bool SupportsTvRageSearch
{
get
{
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
return capabilities . SupportedTvSearchParameters ! = null & &
capabilities . SupportedTvSearchParameters . Contains ( "rid" ) & &
capabilities . SupportedTvSearchParameters . Contains ( "season" ) & &
capabilities . SupportedTvSearchParameters . Contains ( "ep" ) ;
}
}
}
public virtual IList < IEnumerable < IndexerRequest > > GetSearchRequests ( SeasonSearchCriteria searchCriteria )
p rivate bool SupportsTvMazeSearch
{
{
var pageableRequests = new List < IEnumerable < IndexerRequest > > ( ) ;
get
{
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
return capabilities . SupportedTvSearchParameters ! = null & &
capabilities . SupportedTvSearchParameters . Contains ( "tvmazeid" ) & &
capabilities . SupportedTvSearchParameters . Contains ( "season" ) & &
capabilities . SupportedTvSearchParameters . Contains ( "ep" ) ;
}
}
if ( searchCriteria . Series . TvRageId > 0 )
private bool SupportsAggregatedIdSearch
{
get
{
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
String . Format ( "&rid={0}&season={1}" ,
searchCriteria . Series . TvRageId ,
return capabilities . SupportsAggregateIdSearch ;
searchCriteria . SeasonNumber ) ) ) ;
}
}
else
}
public virtual IndexerPageableRequestChain GetRecentRequests ( )
{
var pageableRequests = new IndexerPageableRequestChain ( ) ;
var capabilities = _capabilitiesProvider . GetCapabilities ( Settings ) ;
if ( capabilities . SupportedTvSearchParameters ! = null )
{
{
foreach ( var queryTitle in searchCriteria . QueryTitles )
pageableRequests . Add ( GetPagedRequests ( MaxPages , Settings . Categories . Concat ( Settings . AnimeCategories ) , "tvsearch" , "" ) ) ;
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
String . Format ( "&q={0}&season={1}" ,
NewsnabifyTitle ( queryTitle ) ,
searchCriteria . SeasonNumber ) ) ) ;
}
}
}
return pageableRequests ;
return pageableRequests ;
}
}
public virtual I List< IEnumerable < IndexerRequest > > GetSearchRequests ( Daily EpisodeSearchCriteria searchCriteria )
public virtual IndexerPageableRequestChain GetSearchRequests ( SingleEpisodeSearchCriteria searchCriteria )
{
{
var pageableRequests = new List< IEnumerable < IndexerRequest > > ( ) ;
var pageableRequests = new IndexerPageableRequestChain ( ) ;
if ( searchCriteria . Series . TvRageId > 0 )
AddTvIdPageableRequests ( pageableRequests , MaxPages , Settings . Categories , searchCriteria ,
{
string . Format ( "&season={0}&ep={1}" ,
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
searchCriteria . SeasonNumber ,
String . Format ( "&rid={0}&season={1:yyyy}&ep={1:MM}/{1:dd}" ,
searchCriteria . EpisodeNumber ) ) ;
searchCriteria . Series . TvRageId ,
searchCriteria . AirDate ) ) ) ;
return pageableRequests ;
}
}
else
public virtual IndexerPageableRequestChain GetSearchRequests ( SeasonSearchCriteria searchCriteria )
{
var pageableRequests = new IndexerPageableRequestChain ( ) ;
AddTvIdPageableRequests ( pageableRequests , MaxPages , Settings . Categories , searchCriteria ,
string . Format ( "&season={0}" ,
searchCriteria . SeasonNumber ) ) ;
return pageableRequests ;
}
public virtual IndexerPageableRequestChain GetSearchRequests ( DailyEpisodeSearchCriteria searchCriteria )
{
var pageableRequests = new IndexerPageableRequestChain ( ) ;
AddTvIdPageableRequests ( pageableRequests , MaxPages , Settings . Categories , searchCriteria ,
string . Format ( "&season={0:yyyy}&ep={0:MM}/{0:dd}" ,
searchCriteria . AirDate ) ) ;
return pageableRequests ;
}
public virtual IndexerPageableRequestChain GetSearchRequests ( AnimeEpisodeSearchCriteria searchCriteria )
{
var pageableRequests = new IndexerPageableRequestChain ( ) ;
if ( SupportsSearch )
{
{
foreach ( var queryTitle in searchCriteria . QueryTitles )
foreach ( var queryTitle in searchCriteria . QueryTitles )
{
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
pageableRequests . Add ( GetPagedRequests ( MaxPages , Settings . Anime Categories, " search",
String . Format ( "&q={0}&season={1:yyyy}&ep={1:MM}/{1:dd}" ,
string . Format ( "&q={0}+{1:00 }",
NewsnabifyTitle ( queryTitle ) ,
NewsnabifyTitle ( queryTitle ) ,
searchCriteria . AirDate ) ) ) ;
searchCriteria . A bsoluteEpisodeNumber ) ) ) ;
}
}
}
}
return pageableRequests ;
return pageableRequests ;
}
}
public virtual IList < IEnumerable < IndexerRequest > > GetSearchRequests ( AnimeEpisodeSearchCriteria searchCriteria )
public virtual I ndexerPageableRequestChain GetSearchRequests ( Special EpisodeSearchCriteria searchCriteria )
{
{
var pageableRequests = new List < IEnumerable < IndexerRequest > > ( ) ;
var pageableRequests = new IndexerPageableRequestChain ( ) ;
foreach ( var queryTitle in searchCriteria . QueryTitles )
if ( SupportsSearch )
{
{
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . AnimeCategories , "search" ,
foreach ( var queryTitle in searchCriteria . EpisodeQueryTitles )
String . Format ( "&q={0}+{1:00}" ,
{
NewsnabifyTitle ( queryTitle ) ,
var query = queryTitle . Replace ( '+' , ' ' ) ;
searchCriteria . AbsoluteEpisodeNumber ) ) ) ;
query = System . Web . HttpUtility . UrlEncode ( query ) ;
pageableRequests . Add ( GetPagedRequests ( MaxPages , Settings . Categories . Concat ( Settings . AnimeCategories ) , "search" ,
string . Format ( "&q={0}" ,
query ) ) ) ;
}
}
}
return pageableRequests ;
return pageableRequests ;
}
}
p ublic virtual IList < IEnumerable < IndexerRequest > > GetSearchRequests ( SpecialEpisodeSearchCriteria searchCriteria )
p rivate void AddTvIdPageableRequests ( IndexerPageableRequestChain chain , int maxPages , IEnumerable < int > categories , SearchCriteriaBase searchCriteria , string parameters )
{
{
var pageableRequests = new List < IEnumerable < IndexerRequest > > ( ) ;
if ( SupportsAggregatedIdSearch )
{
var ids = "" ;
if ( searchCriteria . Series . TvdbId > 0 & & SupportsTvdbSearch )
{
ids + = "&tvdbid=" + searchCriteria . Series . TvdbId ;
}
if ( searchCriteria . Series . TvRageId > 0 & & SupportsTvRageSearch )
{
ids + = "&rid=" + searchCriteria . Series . TvRageId ;
}
foreach ( var queryTitle in searchCriteria . EpisodeQueryTitles )
if ( searchCriteria . Series . TvMazeId > 0 & & SupportsTvMazeSearch )
{
ids + = "&tvmazeid=" + searchCriteria . Series . TvMazeId ;
}
chain . Add ( GetPagedRequests ( maxPages , categories , "tvsearch" , ids + parameters ) ) ;
}
else
{
{
var query = queryTitle . Replace ( '+' , ' ' ) ;
if ( searchCriteria . Series . TvdbId > 0 & & SupportsTvdbSearch )
query = System . Web . HttpUtility . UrlEncode ( query ) ;
{
chain . Add ( GetPagedRequests ( maxPages , categories , "tvsearch" ,
string . Format ( "&tvdbid={0}{1}" , searchCriteria . Series . TvdbId , parameters ) ) ) ;
}
else if ( searchCriteria . Series . TvRageId > 0 & & SupportsTvRageSearch )
{
chain . Add ( GetPagedRequests ( maxPages , categories , "tvsearch" ,
string . Format ( "&rid={0}{1}" , searchCriteria . Series . TvRageId , parameters ) ) ) ;
}
pageableRequests . AddIfNotNull ( GetPagedRequests ( MaxPages , Settings . Categories . Concat ( Settings . AnimeCategories ) , "search" ,
else if ( searchCriteria . Series . TvMazeId > 0 & & SupportsTvMazeSearch )
String . Format ( "&q={0}" ,
{
query ) ) ) ;
chain . Add ( GetPagedRequests ( maxPages , categories , "tvsearch" ,
string . Format ( "&tvmazeid={0}{1}" , searchCriteria . Series . TvMazeId , parameters ) ) ) ;
}
}
}
return pageableRequests ;
if ( SupportsTvSearch )
{
chain . AddTier ( ) ;
foreach ( var queryTitle in searchCriteria . QueryTitles )
{
chain . Add ( GetPagedRequests ( MaxPages , Settings . Categories , "tvsearch" ,
string . Format ( "&q={0}{1}" ,
NewsnabifyTitle ( queryTitle ) ,
parameters ) ) ) ;
}
}
}
}
private IEnumerable < IndexerRequest > GetPagedRequests ( Int32 maxPages , IEnumerable < Int32 > categories , String searchType , String parameters )
private IEnumerable < IndexerRequest > GetPagedRequests ( int maxPages , IEnumerable < int > categories , string searchType , s tring parameters )
{
{
if ( categories . Empty ( ) )
if ( categories . Empty ( ) )
{
{
yield break ;
yield break ;
}
}
var categoriesQuery = String . Join ( "," , categories . Distinct ( ) ) ;
var categoriesQuery = s tring. Join ( "," , categories . Distinct ( ) ) ;
var baseUrl = S tring. Format ( "{0}/api?t={1}&cat={2}&extended=1{3}" , Settings . Url . TrimEnd ( '/' ) , searchType , categoriesQuery , Settings . AdditionalParameters ) ;
var baseUrl = s tring. Format ( "{0}/api?t={1}&cat={2}&extended=1{3}" , Settings . Url . TrimEnd ( '/' ) , searchType , categoriesQuery , Settings . AdditionalParameters ) ;
if ( Settings . ApiKey . IsNotNullOrWhiteSpace ( ) )
if ( Settings . ApiKey . IsNotNullOrWhiteSpace ( ) )
{
{
@ -155,18 +255,18 @@ namespace NzbDrone.Core.Indexers.Newznab
if ( PageSize = = 0 )
if ( PageSize = = 0 )
{
{
yield return new IndexerRequest ( S tring. Format ( "{0}{1}" , baseUrl , parameters ) , HttpAccept . Rss ) ;
yield return new IndexerRequest ( s tring. Format ( "{0}{1}" , baseUrl , parameters ) , HttpAccept . Rss ) ;
}
}
else
else
{
{
for ( var page = 0 ; page < maxPages ; page + + )
for ( var page = 0 ; page < maxPages ; page + + )
{
{
yield return new IndexerRequest ( S tring. Format ( "{0}&offset={1}&limit={2}{3}" , baseUrl , page * PageSize , PageSize , parameters ) , HttpAccept . Rss ) ;
yield return new IndexerRequest ( s tring. Format ( "{0}&offset={1}&limit={2}{3}" , baseUrl , page * PageSize , PageSize , parameters ) , HttpAccept . Rss ) ;
}
}
}
}
}
}
private static String NewsnabifyTitle ( S tring title )
private static string NewsnabifyTitle ( s tring title )
{
{
return title . Replace ( "+" , "%20" ) ;
return title . Replace ( "+" , "%20" ) ;
}
}