cardigann: add xml parsing support (#12848)

Co-authored-by: garfield69 <garfieldsixtynine@gmail.com>
Co-authored-by: Qstick
This commit is contained in:
ilike2burnthing 2022-01-19 18:52:45 +00:00 committed by GitHub
parent 0cd4eb2b69
commit ec8e141ac9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 149 deletions

View File

@ -0,0 +1,60 @@
---
id: showrss
name: showRSS
description: "showRSS is a service that allows you to keep track of your favorite TV shows"
language: en-US
type: public
encoding: UTF-8
links:
- https://showrss.info/
caps:
categorymappings:
- {id: 1, cat: TV/SD}
- {id: 2, cat: TV/HD}
modes:
search: [q]
tv-search: [q, season, ep]
settings: []
search:
paths:
- path: /other/all.rss
response:
type: xml
attribute: attributes
rows:
selector: rss > channel > item
filters:
- name: andmatch
fields:
category:
selector: raw_title
filters:
case:
":contains(\"720p\")": 2
":contains(\"1080p\")": 2
"*": 1
title:
selector: raw_title
details:
text: "{{ .Config.sitelink }}"
date:
selector: pubDate
download:
selector: link
size:
text: "512 MB"
seeders:
text: 1
leechers:
text: 1
downloadvolumefactor:
text: 0
uploadvolumefactor:
text: 1
# engine n/a

View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;
using AngleSharp.Xml.Parser;
using Jackett.Common.Helpers;
using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig;
@ -1463,39 +1464,61 @@ namespace Jackett.Common.Indexers
{
try
{
var SearchResultParser = new HtmlParser();
var SearchResultDocument = SearchResultParser.ParseDocument(results);
IHtmlCollection<IElement> rowsDom;
// check if we need to login again
var loginNeeded = CheckIfLoginIsNeeded(response, SearchResultDocument);
if (loginNeeded)
if (SearchPath.Response != null && SearchPath.Response.Type.Equals("xml"))
{
logger.Info(string.Format("CardigannIndexer ({0}): Relogin required", Id));
var LoginResult = await DoLogin();
if (!LoginResult)
throw new Exception(string.Format("Relogin failed"));
await TestLogin();
response = await RequestWithCookiesAsync(searchUrl, method: method, data: queryCollection);
if (response.IsRedirect && SearchPath.Followredirect)
await FollowIfRedirect(response);
var SearchResultParser = new XmlParser();
var SearchResultDocument = SearchResultParser.ParseDocument(results);
if (Search.Preprocessingfilters != null)
{
results = applyFilters(results, Search.Preprocessingfilters, variables);
SearchResultDocument = SearchResultParser.ParseDocument(results);
logger.Debug(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", Definition.Id, results));
}
var rowsSelector = applyGoTemplateText(Search.Rows.Selector, variables);
rowsDom = SearchResultDocument.QuerySelectorAll(rowsSelector);
}
else
{
var SearchResultParser = new HtmlParser();
var SearchResultDocument = SearchResultParser.ParseDocument(results);
// check if we need to login again
var loginNeeded = CheckIfLoginIsNeeded(response, SearchResultDocument);
if (loginNeeded)
{
logger.Info(string.Format("CardigannIndexer ({0}): Relogin required", Id));
var LoginResult = await DoLogin();
if (!LoginResult)
throw new Exception(string.Format("Relogin failed"));
await TestLogin();
response = await RequestWithCookiesAsync(searchUrl, method: method, data: queryCollection);
if (response.IsRedirect && SearchPath.Followredirect)
await FollowIfRedirect(response);
results = response.ContentString;
SearchResultDocument = SearchResultParser.ParseDocument(results);
}
checkForError(response, Definition.Search.Error);
if (Search.Preprocessingfilters != null)
{
results = applyFilters(results, Search.Preprocessingfilters, variables);
SearchResultDocument = SearchResultParser.ParseDocument(results);
logger.Debug(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", Id, results));
}
var rowsSelector = applyGoTemplateText(Search.Rows.Selector, variables);
rowsDom = SearchResultDocument.QuerySelectorAll(rowsSelector);
results = response.ContentString;
SearchResultDocument = SearchResultParser.ParseDocument(results);
}
checkForError(response, Definition.Search.Error);
if (Search.Preprocessingfilters != null)
{
results = applyFilters(results, Search.Preprocessingfilters, variables);
SearchResultDocument = SearchResultParser.ParseDocument(results);
logger.Debug(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", Id, results));
}
var rowsSelector = applyGoTemplateText(Search.Rows.Selector, variables);
var RowsDom = SearchResultDocument.QuerySelectorAll(rowsSelector);
var Rows = new List<IElement>();
foreach (var RowDom in RowsDom)
foreach (var RowDom in rowsDom)
{
Rows.Add(RowDom);
}

View File

@ -1,122 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig;
using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils.Clients;
using Newtonsoft.Json.Linq;
using NLog;
namespace Jackett.Common.Indexers
{
[ExcludeFromCodeCoverage]
public class ShowRSS : BaseWebIndexer
{
private string SearchAllUrl => SiteLink + "other/all.rss";
private string BrowseUrl => SiteLink + "browse/";
public override string[] LegacySiteLinks { get; protected set; } = {
"http://showrss.info/"
};
private new ConfigurationData configData => base.configData;
public ShowRSS(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps,
ICacheService cs)
: base(id: "showrss",
name: "ShowRSS",
description: "showRSS is a service that allows you to keep track of your favorite TV shows",
link: "https://showrss.info/",
caps: new TorznabCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
}
},
configService: configService,
client: wc,
logger: l,
p: ps,
cacheService: cs,
configData: new ConfigurationData())
{
Encoding = Encoding.UTF8;
Language = "en-US";
Type = "public";
AddCategoryMapping(1, TorznabCatType.TV);
AddCategoryMapping(2, TorznabCatType.TVSD);
AddCategoryMapping(3, TorznabCatType.TVHD);
}
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
LoadValuesFromJson(configJson);
var releases = await PerformQuery(new TorznabQuery());
await ConfigureIfOK(string.Empty, releases.Any(),
() => throw new Exception("Could not find releases from this URL"));
return IndexerConfigurationStatus.RequiresTesting;
}
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var episodeSearchUrl = string.Format(SearchAllUrl);
var result = await RequestWithCookiesAndRetryAsync(episodeSearchUrl);
var xmlDoc = new XmlDocument();
try
{
xmlDoc.LoadXml(result.ContentString);
foreach (XmlNode node in xmlDoc.GetElementsByTagName("item"))
{
var title = node.SelectSingleNode(".//*[local-name()='raw_title']").InnerText;
if (!query.MatchQueryStringAND(title))
continue;
// TODO: use Jackett.Common.Utils.TvCategoryParser.ParseTvShowQuality
// guess category from title
var category = title.Contains("720p") || title.Contains("1080p") ?
TorznabCatType.TVHD.ID :
TorznabCatType.TVSD.ID;
var magnetUri = new Uri(node.SelectSingleNode("link")?.InnerText);
var publishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture);
var infoHash = node.SelectSingleNode(".//*[local-name()='info_hash']").InnerText;
var details = new Uri(BrowseUrl + node.SelectSingleNode(".//*[local-name()='show_id']").InnerText);
var release = new ReleaseInfo
{
Title = title,
Details = details,
Category = new List<int> { category },
Guid = magnetUri,
PublishDate = publishDate,
InfoHash = infoHash,
MagnetUri = magnetUri,
Size = 512,
Seeders = 1,
Peers = 2,
DownloadVolumeFactor = 0,
UploadVolumeFactor = 1
};
releases.Add(release);
}
}
catch (Exception e)
{
OnParseError(result.ContentString, e);
}
return releases;
}
}
}

View File

@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="AngleSharp" Version="0.16.1" />
<PackageReference Include="AngleSharp.Xml" Version="0.16.0" />
<PackageReference Include="Autofac" Version="6.3.0" />
<PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="BencodeNET" Version="4.0.0" />