2017-10-26 03:08:37 +00:00
using System ;
using System.Collections.Generic ;
2015-03-12 20:01:54 +00:00
using System.Linq ;
using System.Xml.Linq ;
using NzbDrone.Common.Extensions ;
using NzbDrone.Core.Indexers.Exceptions ;
2023-04-23 23:11:43 +00:00
using NzbDrone.Core.Languages ;
using NzbDrone.Core.Parser ;
2015-03-12 20:01:54 +00:00
using NzbDrone.Core.Parser.Model ;
namespace NzbDrone.Core.Indexers.Torznab
{
public class TorznabRssParser : TorrentRssParser
{
2015-10-03 17:45:26 +00:00
public const string ns = "{http://torznab.com/schemas/2015/feed}" ;
2015-03-12 20:01:54 +00:00
2017-10-26 03:08:37 +00:00
public TorznabRssParser ( )
{
UseEnclosureUrl = true ;
}
2015-03-12 20:01:54 +00:00
protected override bool PreProcess ( IndexerResponse indexerResponse )
{
2023-05-18 13:02:14 +00:00
if ( indexerResponse . HttpResponse . HasHttpError & &
( indexerResponse . HttpResponse . Headers . ContentType = = null | | ! indexerResponse . HttpResponse . Headers . ContentType . Contains ( "xml" ) ) )
2023-05-07 17:29:51 +00:00
{
base . PreProcess ( indexerResponse ) ;
}
2015-09-26 08:45:13 +00:00
var xdoc = LoadXmlDocument ( indexerResponse ) ;
2015-03-12 20:01:54 +00:00
var error = xdoc . Descendants ( "error" ) . FirstOrDefault ( ) ;
2020-01-03 12:49:24 +00:00
if ( error = = null )
{
return true ;
}
2015-03-12 20:01:54 +00:00
var code = Convert . ToInt32 ( error . Attribute ( "code" ) . Value ) ;
var errorMessage = error . Attribute ( "description" ) . Value ;
2020-01-03 12:49:24 +00:00
if ( code > = 100 & & code < = 199 )
{
throw new ApiKeyException ( "Invalid API key" ) ;
}
2015-03-12 20:01:54 +00:00
2016-02-29 23:33:28 +00:00
if ( ! indexerResponse . Request . Url . FullUri . Contains ( "apikey=" ) & & errorMessage = = "Missing parameter" )
2015-03-12 20:01:54 +00:00
{
throw new ApiKeyException ( "Indexer requires an API key" ) ;
}
if ( errorMessage = = "Request limit reached" )
{
throw new RequestLimitReachedException ( "API limit reached" ) ;
}
throw new TorznabException ( "Torznab error detected: {0}" , errorMessage ) ;
}
2017-10-26 03:08:37 +00:00
protected override bool PostProcess ( IndexerResponse indexerResponse , List < XElement > items , List < ReleaseInfo > releases )
2015-03-12 20:01:54 +00:00
{
2017-10-26 03:08:37 +00:00
var enclosureTypes = items . SelectMany ( GetEnclosures ) . Select ( v = > v . Type ) . Distinct ( ) . ToArray ( ) ;
if ( enclosureTypes . Any ( ) & & enclosureTypes . Intersect ( PreferredEnclosureMimeTypes ) . Empty ( ) )
2015-03-12 20:01:54 +00:00
{
2017-10-26 03:08:37 +00:00
if ( enclosureTypes . Intersect ( UsenetEnclosureMimeTypes ) . Any ( ) )
{
2020-10-25 18:47:19 +00:00
_logger . Warn ( "{0} does not contain {1}, found {2}, did you intend to add a Newznab indexer?" , indexerResponse . Request . Url , TorrentEnclosureMimeType , enclosureTypes [ 0 ] ) ;
2017-10-26 03:08:37 +00:00
}
else
{
2020-10-25 18:47:19 +00:00
_logger . Warn ( "{1} does not contain {1}, found {2}." , indexerResponse . Request . Url , TorrentEnclosureMimeType , enclosureTypes [ 0 ] ) ;
2017-10-26 03:08:37 +00:00
}
2015-03-12 20:01:54 +00:00
}
2017-10-26 03:08:37 +00:00
return true ;
2015-03-12 20:01:54 +00:00
}
2024-02-21 04:12:45 +00:00
protected override ReleaseInfo ProcessItem ( XElement item , ReleaseInfo releaseInfo )
{
var torrentInfo = base . ProcessItem ( item , releaseInfo ) as TorrentInfo ;
if ( torrentInfo ! = null )
{
torrentInfo . IndexerFlags = GetFlags ( item ) ;
}
return torrentInfo ;
}
2015-10-03 17:45:26 +00:00
protected override string GetInfoUrl ( XElement item )
2015-03-12 20:01:54 +00:00
{
2015-08-15 10:32:37 +00:00
return ParseUrl ( item . TryGetValue ( "comments" ) . TrimEnd ( "#comments" ) ) ;
2015-03-12 20:01:54 +00:00
}
2015-10-03 17:45:26 +00:00
protected override string GetCommentUrl ( XElement item )
2015-03-12 20:01:54 +00:00
{
2015-08-15 10:32:37 +00:00
return ParseUrl ( item . TryGetValue ( "comments" ) ) ;
2015-03-12 20:01:54 +00:00
}
2023-04-23 23:11:43 +00:00
protected override List < Language > GetLanguages ( XElement item )
{
2023-05-21 16:05:18 +00:00
var languages = TryGetMultipleTorznabAttributes ( item , "language" ) ;
2023-04-23 23:11:43 +00:00
var results = new List < Language > ( ) ;
// Try to find <language> elements for some indexers that suck at following the rules.
2023-05-21 16:05:18 +00:00
if ( languages . Count = = 0 )
2023-04-23 23:11:43 +00:00
{
2023-05-21 16:05:18 +00:00
languages = item . Elements ( "language" ) . Select ( e = > e . Value ) . ToList ( ) ;
2023-04-23 23:11:43 +00:00
}
2023-05-21 16:05:18 +00:00
foreach ( var language in languages )
2023-04-23 23:11:43 +00:00
{
var mappedLanguage = IsoLanguages . FindByName ( language ) ? . Language ? ? null ;
if ( mappedLanguage ! = null )
{
results . Add ( mappedLanguage ) ;
}
}
return results ;
}
2015-09-26 08:45:13 +00:00
protected override long GetSize ( XElement item )
2015-03-12 20:01:54 +00:00
{
var sizeString = TryGetTorznabAttribute ( item , "size" ) ;
2023-05-23 10:48:37 +00:00
if ( ! sizeString . IsNullOrWhiteSpace ( ) & & long . TryParse ( sizeString , out var size ) )
2015-03-12 20:01:54 +00:00
{
return size ;
}
size = GetEnclosureLength ( item ) ;
return size ;
}
protected override DateTime GetPublishDate ( XElement item )
{
return base . GetPublishDate ( item ) ;
}
protected override string GetDownloadUrl ( XElement item )
{
var url = base . GetDownloadUrl ( item ) ;
if ( ! Uri . IsWellFormedUriString ( url , UriKind . Absolute ) )
{
2015-08-15 10:32:37 +00:00
url = ParseUrl ( ( string ) item . Element ( "enclosure" ) . Attribute ( "url" ) ) ;
2015-03-12 20:01:54 +00:00
}
return url ;
}
2015-10-03 17:45:26 +00:00
protected override string GetInfoHash ( XElement item )
2015-03-12 20:01:54 +00:00
{
return TryGetTorznabAttribute ( item , "infohash" ) ;
}
2015-10-03 17:45:26 +00:00
protected override string GetMagnetUrl ( XElement item )
2015-03-12 20:01:54 +00:00
{
return TryGetTorznabAttribute ( item , "magneturl" ) ;
}
2015-09-26 08:45:13 +00:00
protected override int? GetSeeders ( XElement item )
2015-03-12 20:01:54 +00:00
{
var seeders = TryGetTorznabAttribute ( item , "seeders" ) ;
if ( seeders . IsNotNullOrWhiteSpace ( ) )
{
2015-09-26 08:45:13 +00:00
return int . Parse ( seeders ) ;
2015-03-12 20:01:54 +00:00
}
return base . GetSeeders ( item ) ;
}
2015-09-26 08:45:13 +00:00
protected override int? GetPeers ( XElement item )
2015-03-12 20:01:54 +00:00
{
var peers = TryGetTorznabAttribute ( item , "peers" ) ;
if ( peers . IsNotNullOrWhiteSpace ( ) )
{
2015-09-26 08:45:13 +00:00
return int . Parse ( peers ) ;
2015-03-12 20:01:54 +00:00
}
var seeders = TryGetTorznabAttribute ( item , "seeders" ) ;
var leechers = TryGetTorznabAttribute ( item , "leechers" ) ;
if ( seeders . IsNotNullOrWhiteSpace ( ) & & leechers . IsNotNullOrWhiteSpace ( ) )
{
2015-09-26 08:45:13 +00:00
return int . Parse ( seeders ) + int . Parse ( leechers ) ;
2015-03-12 20:01:54 +00:00
}
return base . GetPeers ( item ) ;
}
2024-02-21 04:12:45 +00:00
protected IndexerFlags GetFlags ( XElement item )
{
IndexerFlags flags = 0 ;
var downloadFactor = TryGetFloatTorznabAttribute ( item , "downloadvolumefactor" , 1 ) ;
var uploadFactor = TryGetFloatTorznabAttribute ( item , "uploadvolumefactor" , 1 ) ;
if ( downloadFactor = = 0.5 )
{
flags | = IndexerFlags . Halfleech ;
}
if ( downloadFactor = = 0.75 )
{
flags | = IndexerFlags . Freeleech25 ;
}
if ( downloadFactor = = 0.25 )
{
flags | = IndexerFlags . Freeleech75 ;
}
if ( downloadFactor = = 0.0 )
{
flags | = IndexerFlags . Freeleech ;
}
if ( uploadFactor = = 2.0 )
{
flags | = IndexerFlags . DoubleUpload ;
}
var tags = TryGetMultipleTorznabAttributes ( item , "tag" ) ;
if ( tags . Any ( t = > t . EqualsIgnoreCase ( "internal" ) ) )
{
flags | = IndexerFlags . Internal ;
}
if ( tags . Any ( t = > t . EqualsIgnoreCase ( "scene" ) ) )
{
flags | = IndexerFlags . Scene ;
}
return flags ;
}
2015-10-03 17:45:26 +00:00
protected string TryGetTorznabAttribute ( XElement item , string key , string defaultValue = "" )
2015-03-12 20:01:54 +00:00
{
2017-10-26 03:08:37 +00:00
var attrElement = item . Elements ( ns + "attr" ) . FirstOrDefault ( e = > e . Attribute ( "name" ) . Value . Equals ( key , StringComparison . OrdinalIgnoreCase ) ) ;
if ( attrElement ! = null )
2015-03-12 20:01:54 +00:00
{
2017-10-26 03:08:37 +00:00
var attrValue = attrElement . Attribute ( "value" ) ;
if ( attrValue ! = null )
{
return attrValue . Value ;
}
2015-03-12 20:01:54 +00:00
}
return defaultValue ;
}
2023-04-23 23:11:43 +00:00
2024-02-21 04:12:45 +00:00
protected float TryGetFloatTorznabAttribute ( XElement item , string key , float defaultValue = 0 )
{
var attr = TryGetTorznabAttribute ( item , key , defaultValue . ToString ( ) ) ;
return float . TryParse ( attr , out var result ) ? result : defaultValue ;
}
2023-04-23 23:11:43 +00:00
protected List < string > TryGetMultipleTorznabAttributes ( XElement item , string key )
{
var attrElements = item . Elements ( ns + "attr" ) . Where ( e = > e . Attribute ( "name" ) . Value . Equals ( key , StringComparison . OrdinalIgnoreCase ) ) ;
var results = new List < string > ( ) ;
foreach ( var element in attrElements )
{
var attrValue = element . Attribute ( "value" ) ;
if ( attrValue ! = null )
{
results . Add ( attrValue . Value ) ;
}
}
return results ;
}
2015-03-12 20:01:54 +00:00
}
}