2018-05-12 01:55:24 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.Specialized;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using AngleSharp.Parser.Html;
|
|
|
|
|
using Jackett.Common.Models;
|
|
|
|
|
using Jackett.Common.Models.IndexerConfig;
|
|
|
|
|
using Jackett.Common.Services.Interfaces;
|
|
|
|
|
using Jackett.Common.Utils;
|
|
|
|
|
using Jackett.Common.Utils.Clients;
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
using NLog;
|
|
|
|
|
using static Jackett.Common.Models.IndexerConfig.ConfigurationData;
|
|
|
|
|
|
|
|
|
|
namespace Jackett.Common.Indexers
|
|
|
|
|
{
|
|
|
|
|
public class Newpct : BaseCachingWebIndexer
|
|
|
|
|
{
|
|
|
|
|
enum ReleaseType
|
|
|
|
|
{
|
|
|
|
|
TV,
|
|
|
|
|
Movie,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class NewpctRelease : ReleaseInfo
|
|
|
|
|
{
|
2018-08-29 09:21:07 +00:00
|
|
|
|
public ReleaseType NewpctReleaseType;
|
|
|
|
|
public string SeriesName;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
public int? Season;
|
|
|
|
|
public int? Episode;
|
|
|
|
|
public int? EpisodeTo;
|
2018-11-19 10:50:24 +00:00
|
|
|
|
public int Score;
|
2018-08-29 09:21:07 +00:00
|
|
|
|
|
|
|
|
|
public NewpctRelease()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 10:50:24 +00:00
|
|
|
|
public NewpctRelease(NewpctRelease copyFrom) :
|
2018-08-29 09:21:07 +00:00
|
|
|
|
base(copyFrom)
|
|
|
|
|
{
|
|
|
|
|
NewpctReleaseType = copyFrom.NewpctReleaseType;
|
|
|
|
|
SeriesName = copyFrom.SeriesName;
|
|
|
|
|
Season = copyFrom.Season;
|
|
|
|
|
Episode = copyFrom.Episode;
|
|
|
|
|
EpisodeTo = copyFrom.EpisodeTo;
|
2018-11-19 10:50:24 +00:00
|
|
|
|
Score = copyFrom.Score;
|
2018-08-29 09:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override object Clone()
|
|
|
|
|
{
|
|
|
|
|
return new NewpctRelease(this);
|
|
|
|
|
}
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-16 00:40:40 +00:00
|
|
|
|
private static Uri DefaultSiteLinkUri =
|
|
|
|
|
new Uri("http://descargas2020.com/");
|
|
|
|
|
|
|
|
|
|
private static Uri[] ExtraSiteLinkUris = new Uri[]
|
|
|
|
|
{
|
|
|
|
|
new Uri("http://torrentrapid.com/"),
|
|
|
|
|
new Uri("http://torrentlocura.com/"),
|
|
|
|
|
new Uri("http://tumejortorrent.com/"),
|
|
|
|
|
new Uri("http://pctnew.com/"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private static Uri[] LegacySiteLinkUris = new Uri[]
|
2018-12-14 21:56:33 +00:00
|
|
|
|
{
|
2018-12-16 00:40:40 +00:00
|
|
|
|
new Uri("http://www.tvsinpagar.com/"),
|
2018-12-14 21:56:33 +00:00
|
|
|
|
};
|
|
|
|
|
|
2018-08-29 09:21:07 +00:00
|
|
|
|
private NewpctRelease _mostRecentRelease;
|
2018-12-14 21:56:33 +00:00
|
|
|
|
private char[] _wordSeparators = new char[] { ' ', '.', ',', ';', '(', ')', '[', ']', '-', '_' };
|
2018-11-19 10:50:24 +00:00
|
|
|
|
private int _wordNotFoundScore = 100000;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
private Regex _searchStringRegex = new Regex(@"(.+?)S0?(\d+)(E0?(\d+))?$", RegexOptions.IgnoreCase);
|
2018-08-29 09:21:07 +00:00
|
|
|
|
private Regex _titleListRegex = new Regex(@"Serie( *Descargar)?(.+?)(Temporada(.+?)(\d+)(.+?))?Capitulos?(.+?)(\d+)((.+?)(\d+))?(.+?)-(.+?)Calidad(.*)", RegexOptions.IgnoreCase);
|
2018-07-03 09:01:08 +00:00
|
|
|
|
private Regex _titleClassicRegex = new Regex(@"(\[[^\]]*\])?\[Cap\.(\d{1,2})(\d{2})([_-](\d{1,2})(\d{2}))?\]", RegexOptions.IgnoreCase);
|
2018-05-12 01:55:24 +00:00
|
|
|
|
private Regex _titleClassicTvQualityRegex = new Regex(@"\[([^\]]*HDTV[^\]]*)", RegexOptions.IgnoreCase);
|
|
|
|
|
|
|
|
|
|
private int _maxDailyPages = 7;
|
2018-12-14 21:56:33 +00:00
|
|
|
|
private int _maxMoviesPages = 30;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
private int _maxEpisodesListPages = 100;
|
|
|
|
|
private int[] _allTvCategories = TorznabCatType.TV.SubCategories.Select(c => c.ID).ToArray();
|
2018-11-19 10:50:24 +00:00
|
|
|
|
private int[] _allMoviesCategories = TorznabCatType.Movies.SubCategories.Select(c => c.ID).ToArray();
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-10-20 05:48:53 +00:00
|
|
|
|
private bool _includeVo;
|
2018-11-19 10:50:24 +00:00
|
|
|
|
private bool _filterMovies;
|
2018-08-29 09:21:07 +00:00
|
|
|
|
private DateTime _dailyNow;
|
|
|
|
|
private int _dailyResultIdx;
|
|
|
|
|
|
2018-11-19 10:50:24 +00:00
|
|
|
|
private string _searchUrl = "/buscar";
|
2018-05-12 01:55:24 +00:00
|
|
|
|
private string _dailyUrl = "/ultimas-descargas/pg/{0}";
|
|
|
|
|
private string[] _seriesLetterUrls = new string[] { "/series/letter/{0}", "/series-hd/letter/{0}" };
|
|
|
|
|
private string[] _seriesVOLetterUrls = new string[] { "/series-vo/letter/{0}" };
|
|
|
|
|
private string _seriesUrl = "{0}/pg/{1}";
|
2018-10-20 05:48:53 +00:00
|
|
|
|
private string[] _voUrls = new string[] { "serie-vo", "serievo" };
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-12-16 00:40:40 +00:00
|
|
|
|
public override string[] LegacySiteLinks { get; protected set; } = LegacySiteLinkUris.Select(u => u.AbsoluteUri).ToArray();
|
|
|
|
|
|
2018-05-12 01:55:24 +00:00
|
|
|
|
public Newpct(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps)
|
|
|
|
|
: base(name: "Newpct",
|
|
|
|
|
description: "Newpct - descargar torrent peliculas, series",
|
2018-12-16 00:40:40 +00:00
|
|
|
|
link: DefaultSiteLinkUri.AbsoluteUri,
|
2018-05-12 01:55:24 +00:00
|
|
|
|
caps: new TorznabCapabilities(TorznabCatType.TV,
|
|
|
|
|
TorznabCatType.TVSD,
|
|
|
|
|
TorznabCatType.TVHD,
|
|
|
|
|
TorznabCatType.Movies),
|
|
|
|
|
configService: configService,
|
|
|
|
|
client: wc,
|
|
|
|
|
logger: l,
|
|
|
|
|
p: ps,
|
|
|
|
|
configData: new ConfigurationData())
|
|
|
|
|
{
|
|
|
|
|
Encoding = Encoding.GetEncoding("windows-1252");
|
|
|
|
|
Language = "es-es";
|
|
|
|
|
Type = "public";
|
|
|
|
|
|
|
|
|
|
var voItem = new BoolItem() { Name = "Include original versions in search results", Value = false };
|
|
|
|
|
configData.AddDynamic("IncludeVo", voItem);
|
2018-11-19 10:50:24 +00:00
|
|
|
|
|
|
|
|
|
var filterMoviesItem = new BoolItem() { Name = "Only full match movies", Value = true };
|
|
|
|
|
configData.AddDynamic("FilterMovies", filterMoviesItem);
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
|
|
|
|
{
|
|
|
|
|
configData.LoadValuesFromJson(configJson);
|
|
|
|
|
var releases = await PerformQuery(new TorznabQuery());
|
|
|
|
|
|
|
|
|
|
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Could not find releases from this URL");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return IndexerConfigurationStatus.Completed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
|
|
|
|
{
|
2018-12-14 21:56:33 +00:00
|
|
|
|
Uri link = new Uri(configData.SiteLink.Value);
|
|
|
|
|
|
|
|
|
|
lock (cache)
|
|
|
|
|
{
|
|
|
|
|
CleanCache();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await PerformQuery(link, query, 0);
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
public override async Task<byte[]> Download(Uri linkParam)
|
2018-05-12 01:55:24 +00:00
|
|
|
|
{
|
2018-12-14 21:56:33 +00:00
|
|
|
|
List<string> links = new List<string>();
|
|
|
|
|
links.Add(linkParam.AbsoluteUri);
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-12-16 00:40:40 +00:00
|
|
|
|
IEnumerable<Uri> knownUris = (new Uri[] { DefaultSiteLinkUri }).
|
|
|
|
|
Concat(ExtraSiteLinkUris).Concat(LegacySiteLinkUris);
|
|
|
|
|
|
|
|
|
|
foreach (Uri extraSiteUri in knownUris)
|
2018-12-14 21:56:33 +00:00
|
|
|
|
{
|
|
|
|
|
UriBuilder ub = new UriBuilder(linkParam);
|
|
|
|
|
ub.Host = extraSiteUri.Host;
|
2018-12-16 00:40:40 +00:00
|
|
|
|
string link = ub.Uri.AbsoluteUri;
|
|
|
|
|
if (link != linkParam.AbsoluteUri)
|
|
|
|
|
links.Add(ub.Uri.AbsoluteUri);
|
2018-12-14 21:56:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (string link in links)
|
|
|
|
|
{
|
|
|
|
|
byte[] result = null;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var results = await RequestStringWithCookies(link);
|
|
|
|
|
var content = results.Content;
|
|
|
|
|
|
|
|
|
|
Regex regex = new Regex("[^\"]*/descargar-torrent/\\d+_[^\"]*");
|
|
|
|
|
Match match = regex.Match(content);
|
|
|
|
|
if (match.Success)
|
|
|
|
|
result = await base.Download(new Uri(match.Groups[0].Value));
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result != null)
|
|
|
|
|
return result;
|
|
|
|
|
else
|
|
|
|
|
this.logger.Warn("Newpct - download link not found in " + link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
private async Task<IEnumerable<ReleaseInfo>> PerformQuery(Uri siteLink, TorznabQuery query, int attempts)
|
2018-05-12 01:55:24 +00:00
|
|
|
|
{
|
|
|
|
|
var releases = new List<ReleaseInfo>();
|
|
|
|
|
|
2018-10-20 05:48:53 +00:00
|
|
|
|
_includeVo = ((BoolItem)configData.GetDynamic("IncludeVo")).Value;
|
2018-11-19 10:50:24 +00:00
|
|
|
|
_filterMovies = ((BoolItem)configData.GetDynamic("FilterMovies")).Value;
|
2018-08-29 09:21:07 +00:00
|
|
|
|
_dailyNow = DateTime.Now;
|
|
|
|
|
_dailyResultIdx = 0;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
bool rssMode = string.IsNullOrEmpty(query.SanitizedSearchTerm);
|
|
|
|
|
|
|
|
|
|
if (rssMode)
|
|
|
|
|
{
|
|
|
|
|
int pg = 1;
|
|
|
|
|
while (pg <= _maxDailyPages)
|
|
|
|
|
{
|
2018-12-14 21:56:33 +00:00
|
|
|
|
Uri url = new Uri(siteLink, string.Format(_dailyUrl, pg));
|
2018-05-12 01:55:24 +00:00
|
|
|
|
var results = await RequestStringWithCookies(url.AbsoluteUri);
|
|
|
|
|
|
|
|
|
|
var items = ParseDailyContent(results.Content);
|
|
|
|
|
if (items == null || !items.Any())
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
releases.AddRange(items);
|
|
|
|
|
|
|
|
|
|
//Check if we need to go to next page
|
|
|
|
|
bool recentFound = _mostRecentRelease != null &&
|
|
|
|
|
items.Any(r => r.Title == _mostRecentRelease.Title && r.Link.AbsoluteUri == _mostRecentRelease.Link.AbsoluteUri);
|
|
|
|
|
if (pg == 1)
|
2018-08-29 09:21:07 +00:00
|
|
|
|
_mostRecentRelease = (NewpctRelease)items.First().Clone();
|
2018-05-12 01:55:24 +00:00
|
|
|
|
if (recentFound)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
pg++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool isTvSearch = query.Categories == null || query.Categories.Length == 0 ||
|
|
|
|
|
query.Categories.Any(c => _allTvCategories.Contains(c));
|
|
|
|
|
if (isTvSearch)
|
|
|
|
|
{
|
2018-12-14 21:56:33 +00:00
|
|
|
|
releases.AddRange(await TvSearch(siteLink, query));
|
2018-11-19 10:50:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isMovieSearch = query.Categories == null || query.Categories.Length == 0 ||
|
|
|
|
|
query.Categories.Any(c => _allMoviesCategories.Contains(c));
|
|
|
|
|
if (isMovieSearch)
|
|
|
|
|
{
|
2018-12-14 21:56:33 +00:00
|
|
|
|
releases.AddRange(await MovieSearch(siteLink, query));
|
2018-07-03 12:29:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-07-03 12:29:06 +00:00
|
|
|
|
return releases;
|
|
|
|
|
}
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
private async Task<IEnumerable<ReleaseInfo>> TvSearch(Uri siteLink, TorznabQuery query)
|
2018-07-03 12:29:06 +00:00
|
|
|
|
{
|
2018-10-20 05:48:53 +00:00
|
|
|
|
List<ReleaseInfo> newpctReleases = null;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-07-03 12:29:06 +00:00
|
|
|
|
string seriesName = query.SanitizedSearchTerm;
|
|
|
|
|
int? season = query.Season > 0 ? (int?)query.Season : null;
|
|
|
|
|
int? episode = null;
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(query.Episode) && int.TryParse(query.Episode, out int episodeTemp))
|
|
|
|
|
episode = episodeTemp;
|
|
|
|
|
|
|
|
|
|
//If query has no season/episode info, try to parse title
|
|
|
|
|
if (season == null && episode == null)
|
|
|
|
|
{
|
|
|
|
|
Match searchMatch = _searchStringRegex.Match(query.SanitizedSearchTerm);
|
|
|
|
|
if (searchMatch.Success)
|
|
|
|
|
{
|
|
|
|
|
seriesName = searchMatch.Groups[1].Value.Trim();
|
|
|
|
|
season = int.Parse(searchMatch.Groups[2].Value);
|
|
|
|
|
episode = searchMatch.Groups[4].Success ? (int?)int.Parse(searchMatch.Groups[4].Value) : null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-07-03 12:29:06 +00:00
|
|
|
|
//Try to reuse cache
|
|
|
|
|
lock (cache)
|
|
|
|
|
{
|
|
|
|
|
var cachedResult = cache.FirstOrDefault(i => i.Query == seriesName.ToLower());
|
2018-08-29 09:21:07 +00:00
|
|
|
|
if (cachedResult != null)
|
|
|
|
|
newpctReleases = cachedResult.Results.Select(r => (ReleaseInfo)r.Clone()).ToList();
|
2018-07-03 12:29:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-29 09:21:07 +00:00
|
|
|
|
if (newpctReleases == null)
|
2018-07-03 12:29:06 +00:00
|
|
|
|
{
|
2018-08-29 09:21:07 +00:00
|
|
|
|
newpctReleases = new List<ReleaseInfo>();
|
|
|
|
|
|
2018-07-03 12:29:06 +00:00
|
|
|
|
//Search series url
|
2018-12-14 21:56:33 +00:00
|
|
|
|
foreach (Uri seriesListUrl in SeriesListUris(siteLink, seriesName))
|
2018-07-03 12:29:06 +00:00
|
|
|
|
{
|
|
|
|
|
newpctReleases.AddRange(await GetReleasesFromUri(seriesListUrl, seriesName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Sonarr removes "the" from shows. If there is nothing try prepending "the"
|
|
|
|
|
if (newpctReleases.Count == 0 && !(seriesName.ToLower().StartsWith("the")))
|
|
|
|
|
{
|
|
|
|
|
seriesName = "The " + seriesName;
|
2018-12-14 21:56:33 +00:00
|
|
|
|
foreach (Uri seriesListUrl in SeriesListUris(siteLink, seriesName))
|
2018-05-12 01:55:24 +00:00
|
|
|
|
{
|
2018-07-03 12:29:06 +00:00
|
|
|
|
newpctReleases.AddRange(await GetReleasesFromUri(seriesListUrl, seriesName));
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
2018-07-03 12:29:06 +00:00
|
|
|
|
}
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
2018-07-03 12:29:06 +00:00
|
|
|
|
//Cache ALL episodes
|
|
|
|
|
lock (cache)
|
|
|
|
|
{
|
|
|
|
|
cache.Add(new CachedQueryResult(seriesName.ToLower(), newpctReleases));
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 12:29:06 +00:00
|
|
|
|
//Filter only episodes needed
|
|
|
|
|
return newpctReleases.Where(r =>
|
|
|
|
|
{
|
|
|
|
|
NewpctRelease nr = r as NewpctRelease;
|
2018-10-20 05:48:53 +00:00
|
|
|
|
return (
|
|
|
|
|
nr.Season.HasValue != season.HasValue || //Can't determine if same season
|
2018-07-03 12:29:06 +00:00
|
|
|
|
nr.Season.HasValue && season.Value == nr.Season.Value && //Same season and ...
|
|
|
|
|
(
|
|
|
|
|
nr.Episode.HasValue != episode.HasValue || //Can't determine if same episode
|
|
|
|
|
nr.Episode.HasValue &&
|
|
|
|
|
(
|
|
|
|
|
nr.Episode.Value == episode.Value || //Same episode
|
|
|
|
|
nr.EpisodeTo.HasValue && episode.Value >= nr.Episode.Value && episode.Value <= nr.EpisodeTo.Value //Episode in interval
|
|
|
|
|
)
|
2018-10-20 05:48:53 +00:00
|
|
|
|
)
|
|
|
|
|
);
|
2018-07-03 12:29:06 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<IEnumerable<ReleaseInfo>> GetReleasesFromUri(Uri uri, string seriesName)
|
|
|
|
|
{
|
|
|
|
|
var newpctReleases = new List<ReleaseInfo>();
|
|
|
|
|
var results = await RequestStringWithCookies(uri.AbsoluteUri);
|
|
|
|
|
|
|
|
|
|
//Episodes list
|
|
|
|
|
string seriesEpisodesUrl = ParseSeriesListContent(results.Content, seriesName);
|
|
|
|
|
if (!string.IsNullOrEmpty(seriesEpisodesUrl))
|
|
|
|
|
{
|
|
|
|
|
int pg = 1;
|
|
|
|
|
while (pg < _maxEpisodesListPages)
|
|
|
|
|
{
|
|
|
|
|
Uri episodesListUrl = new Uri(string.Format(_seriesUrl, seriesEpisodesUrl, pg));
|
|
|
|
|
results = await RequestStringWithCookies(episodesListUrl.AbsoluteUri);
|
|
|
|
|
|
|
|
|
|
var items = ParseEpisodesListContent(results.Content);
|
|
|
|
|
if (items == null || !items.Any())
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
newpctReleases.AddRange(items);
|
|
|
|
|
|
|
|
|
|
pg++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return newpctReleases;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
private IEnumerable<Uri> SeriesListUris(Uri siteLink, string seriesName)
|
2018-07-03 12:29:06 +00:00
|
|
|
|
{
|
|
|
|
|
IEnumerable<string> lettersUrl;
|
2018-10-20 05:48:53 +00:00
|
|
|
|
if (!_includeVo)
|
2018-07-03 12:29:06 +00:00
|
|
|
|
{
|
|
|
|
|
lettersUrl = _seriesLetterUrls;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lettersUrl = _seriesLetterUrls.Concat(_seriesVOLetterUrls);
|
|
|
|
|
}
|
|
|
|
|
string seriesLetter = !char.IsDigit(seriesName[0]) ? seriesName[0].ToString() : "0-9";
|
|
|
|
|
return lettersUrl.Select(urlFormat =>
|
|
|
|
|
{
|
2018-12-14 21:56:33 +00:00
|
|
|
|
return new Uri(siteLink, string.Format(urlFormat, seriesLetter.ToLower()));
|
2018-07-03 12:29:06 +00:00
|
|
|
|
});
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IEnumerable<NewpctRelease> ParseDailyContent(string content)
|
|
|
|
|
{
|
|
|
|
|
var SearchResultParser = new HtmlParser();
|
|
|
|
|
var doc = SearchResultParser.Parse(content);
|
|
|
|
|
|
|
|
|
|
List<NewpctRelease> releases = new List<NewpctRelease>();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var rows = doc.QuerySelectorAll(".content .info");
|
|
|
|
|
foreach (var row in rows)
|
|
|
|
|
{
|
|
|
|
|
var anchor = row.QuerySelector("a");
|
2018-08-29 09:21:07 +00:00
|
|
|
|
var title = Regex.Replace(anchor.TextContent, @"\s+", " ").Trim();
|
|
|
|
|
var title2 = Regex.Replace(anchor.GetAttribute("title"), @"\s+", " ").Trim();
|
|
|
|
|
if (title2.Length >= title.Length)
|
|
|
|
|
title = title2;
|
|
|
|
|
|
2018-05-12 01:55:24 +00:00
|
|
|
|
var detailsUrl = anchor.GetAttribute("href");
|
2018-10-20 05:48:53 +00:00
|
|
|
|
if (!_includeVo && _voUrls.Any(vo => detailsUrl.ToLower().Contains(vo.ToLower())))
|
|
|
|
|
continue;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
|
|
|
|
var span = row.QuerySelector("span");
|
|
|
|
|
var quality = span.ChildNodes[0].TextContent.Trim();
|
|
|
|
|
ReleaseType releaseType = ReleaseTypeFromQuality(quality);
|
|
|
|
|
var sizeText = span.ChildNodes[1].TextContent.Replace("Tama\u00F1o", "").Trim();
|
|
|
|
|
|
|
|
|
|
var div = row.QuerySelector("div");
|
|
|
|
|
var language = div.ChildNodes[1].TextContent.Trim();
|
2018-08-29 09:21:07 +00:00
|
|
|
|
_dailyResultIdx++;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
|
|
|
|
NewpctRelease newpctRelease;
|
|
|
|
|
if (releaseType == ReleaseType.TV)
|
2018-10-20 05:48:53 +00:00
|
|
|
|
newpctRelease = GetReleaseFromData(releaseType,
|
2018-05-12 01:55:24 +00:00
|
|
|
|
string.Format("Serie {0} - {1} Calidad [{2}]", title, language, quality),
|
2018-08-29 09:21:07 +00:00
|
|
|
|
detailsUrl, quality, language, ReleaseInfo.GetBytes(sizeText), _dailyNow - TimeSpan.FromMilliseconds(_dailyResultIdx));
|
2018-05-12 01:55:24 +00:00
|
|
|
|
else
|
|
|
|
|
newpctRelease = GetReleaseFromData(releaseType,
|
2018-10-20 05:48:53 +00:00
|
|
|
|
string.Format("{0} [{1}][{2}]", title, quality, language),
|
2018-08-29 09:21:07 +00:00
|
|
|
|
detailsUrl, quality, language, ReleaseInfo.GetBytes(sizeText), _dailyNow - TimeSpan.FromMilliseconds(_dailyResultIdx));
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
|
|
|
|
releases.Add(newpctRelease);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
OnParseError(content, ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return releases;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string ParseSeriesListContent(string content, string title)
|
|
|
|
|
{
|
|
|
|
|
var SearchResultParser = new HtmlParser();
|
|
|
|
|
var doc = SearchResultParser.Parse(content);
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> results = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var rows = doc.QuerySelectorAll(".pelilist li a");
|
|
|
|
|
foreach (var anchor in rows)
|
|
|
|
|
{
|
|
|
|
|
var h2 = anchor.QuerySelector("h2");
|
|
|
|
|
if (h2.TextContent.Trim().ToLower() == title.Trim().ToLower())
|
|
|
|
|
return anchor.GetAttribute("href");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
OnParseError(content, ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IEnumerable<NewpctRelease> ParseEpisodesListContent(string content)
|
|
|
|
|
{
|
|
|
|
|
var SearchResultParser = new HtmlParser();
|
|
|
|
|
var doc = SearchResultParser.Parse(content);
|
|
|
|
|
|
|
|
|
|
List<NewpctRelease> releases = new List<NewpctRelease>();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var rows = doc.QuerySelectorAll(".content .info");
|
|
|
|
|
foreach (var row in rows)
|
|
|
|
|
{
|
|
|
|
|
var anchor = row.QuerySelector("a");
|
|
|
|
|
var title = anchor.TextContent.Replace("\t", "").Trim();
|
|
|
|
|
var detailsUrl = anchor.GetAttribute("href");
|
|
|
|
|
|
|
|
|
|
var span = row.QuerySelector("span");
|
|
|
|
|
var pubDateText = row.ChildNodes[3].TextContent.Trim();
|
|
|
|
|
var sizeText = row.ChildNodes[5].TextContent.Trim();
|
|
|
|
|
|
|
|
|
|
long size = ReleaseInfo.GetBytes(sizeText);
|
|
|
|
|
DateTime publishDate = DateTime.ParseExact(pubDateText, "dd-MM-yyyy", null);
|
|
|
|
|
NewpctRelease newpctRelease = GetReleaseFromData(ReleaseType.TV, title, detailsUrl, null, null, size, publishDate);
|
|
|
|
|
|
|
|
|
|
releases.Add(newpctRelease);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
OnParseError(content, ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return releases;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
private async Task<IEnumerable<ReleaseInfo>> MovieSearch(Uri siteLink, TorznabQuery query)
|
2018-11-19 10:50:24 +00:00
|
|
|
|
{
|
|
|
|
|
var releases = new List<NewpctRelease>();
|
|
|
|
|
|
|
|
|
|
string searchStr = query.SanitizedSearchTerm;
|
|
|
|
|
|
|
|
|
|
int pg = 1;
|
|
|
|
|
while (pg <= _maxMoviesPages)
|
|
|
|
|
{
|
|
|
|
|
var queryCollection = new Dictionary<string, string>();
|
|
|
|
|
queryCollection.Add("q", searchStr);
|
|
|
|
|
queryCollection.Add("pg", pg.ToString());
|
|
|
|
|
|
2018-12-14 21:56:33 +00:00
|
|
|
|
Uri url = new Uri(siteLink, string.Format(_searchUrl, pg));
|
2018-11-19 10:50:24 +00:00
|
|
|
|
var results = await PostDataWithCookies(url.AbsoluteUri, queryCollection);
|
|
|
|
|
|
|
|
|
|
var items = ParseSearchContent(results.Content);
|
2018-12-14 21:56:33 +00:00
|
|
|
|
if (items == null)
|
2018-11-19 10:50:24 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
releases.AddRange(items);
|
|
|
|
|
pg++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScoreReleases(releases, searchStr);
|
|
|
|
|
|
|
|
|
|
if (_filterMovies)
|
|
|
|
|
releases = releases.Where(r => r.Score < _wordNotFoundScore).ToList();
|
|
|
|
|
|
|
|
|
|
return releases;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IEnumerable<NewpctRelease> ParseSearchContent(string content)
|
|
|
|
|
{
|
|
|
|
|
var SearchResultParser = new HtmlParser();
|
|
|
|
|
var doc = SearchResultParser.Parse(content);
|
|
|
|
|
|
|
|
|
|
List<NewpctRelease> releases = new List<NewpctRelease>();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var rows = doc.QuerySelectorAll(".content .info");
|
2018-12-14 21:56:33 +00:00
|
|
|
|
if (rows == null || !rows.Any())
|
|
|
|
|
return null;
|
2018-11-19 10:50:24 +00:00
|
|
|
|
foreach (var row in rows)
|
|
|
|
|
{
|
|
|
|
|
var anchor = row.QuerySelector("a");
|
|
|
|
|
var h2 = anchor.QuerySelector("h2");
|
|
|
|
|
var title = Regex.Replace(h2.TextContent, @"\s+", " ").Trim();
|
|
|
|
|
var detailsUrl = anchor.GetAttribute("href");
|
|
|
|
|
|
|
|
|
|
bool isSeries = h2.QuerySelector("span") != null && h2.TextContent.ToLower().Contains("calidad");
|
|
|
|
|
bool isGame = title.ToLower().Contains("pcdvd");
|
|
|
|
|
if (isSeries || isGame)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var span = row.QuerySelectorAll("span");
|
|
|
|
|
|
|
|
|
|
var pubDateText = span[1].TextContent.Trim();
|
|
|
|
|
var sizeText = span[2].TextContent.Trim();
|
|
|
|
|
|
2019-01-10 14:53:15 +00:00
|
|
|
|
long size = 0;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
size = ReleaseInfo.GetBytes(sizeText);
|
|
|
|
|
} catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
DateTime publishDate;
|
|
|
|
|
DateTime.TryParseExact(pubDateText, "dd-MM-yyyy", null, DateTimeStyles.None, out publishDate);
|
2018-11-19 10:50:24 +00:00
|
|
|
|
|
|
|
|
|
var div = row.QuerySelector("div");
|
|
|
|
|
|
|
|
|
|
NewpctRelease newpctRelease;
|
|
|
|
|
newpctRelease = GetReleaseFromData(ReleaseType.Movie, title, detailsUrl, null, null, size, publishDate);
|
|
|
|
|
|
|
|
|
|
releases.Add(newpctRelease);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
OnParseError(content, ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return releases;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ScoreReleases(IEnumerable<NewpctRelease> releases, string searchTerm)
|
|
|
|
|
{
|
|
|
|
|
string[] searchWords = searchTerm.ToLower().Split(_wordSeparators, StringSplitOptions.None).
|
|
|
|
|
Select(s => s.Trim()).
|
|
|
|
|
Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
|
|
|
|
|
|
|
|
|
foreach (NewpctRelease release in releases)
|
|
|
|
|
{
|
|
|
|
|
release.Score = 0;
|
|
|
|
|
string[] releaseWords = release.Title.ToLower().Split(_wordSeparators, StringSplitOptions.None).
|
|
|
|
|
Select(s => s.Trim()).
|
|
|
|
|
Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
|
|
|
|
|
|
|
|
|
foreach (string search in searchWords)
|
|
|
|
|
{
|
|
|
|
|
int index = Array.IndexOf(releaseWords, search);
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
release.Score += index;
|
|
|
|
|
releaseWords[index] = null;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
release.Score += _wordNotFoundScore;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-12 01:55:24 +00:00
|
|
|
|
ReleaseType ReleaseTypeFromQuality(string quality)
|
|
|
|
|
{
|
|
|
|
|
if (quality.Trim().ToLower().StartsWith("hdtv"))
|
|
|
|
|
return ReleaseType.TV;
|
|
|
|
|
else
|
|
|
|
|
return ReleaseType.Movie;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NewpctRelease GetReleaseFromData(ReleaseType releaseType, string title, string detailsUrl, string quality, string language, long size, DateTime publishDate)
|
|
|
|
|
{
|
|
|
|
|
NewpctRelease result = new NewpctRelease();
|
2018-08-29 09:21:07 +00:00
|
|
|
|
result.NewpctReleaseType = releaseType;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
|
|
|
|
//Sanitize
|
|
|
|
|
title = title.Replace("\t", "").Replace("\x2013", "-");
|
|
|
|
|
|
|
|
|
|
Match match = _titleListRegex.Match(title);
|
|
|
|
|
if (match.Success)
|
|
|
|
|
{
|
2018-08-29 09:21:07 +00:00
|
|
|
|
result.SeriesName = match.Groups[2].Value.Trim(' ', '-');
|
|
|
|
|
result.Season = int.Parse(match.Groups[5].Success ? match.Groups[5].Value.Trim() : "1");
|
|
|
|
|
result.Episode = int.Parse(match.Groups[8].Value.Trim().PadLeft(2, '0'));
|
|
|
|
|
result.EpisodeTo = match.Groups[11].Success ? (int?)int.Parse(match.Groups[11].Value.Trim()) : null;
|
|
|
|
|
string audioQuality = match.Groups[13].Value.Trim(' ', '[', ']');
|
2018-10-20 05:48:53 +00:00
|
|
|
|
if (string.IsNullOrEmpty(language))
|
|
|
|
|
language = audioQuality;
|
2018-08-29 09:21:07 +00:00
|
|
|
|
quality = match.Groups[14].Value.Trim(' ', '[', ']');
|
2018-05-12 01:55:24 +00:00
|
|
|
|
|
|
|
|
|
string seasonText = result.Season.ToString();
|
|
|
|
|
string episodeText = seasonText + result.Episode.ToString().PadLeft(2, '0');
|
|
|
|
|
string episodeToText = result.EpisodeTo.HasValue ? "_" + seasonText + result.EpisodeTo.ToString().PadLeft(2, '0') : "";
|
|
|
|
|
|
|
|
|
|
result.Title = string.Format("{0} - Temporada {1} [{2}][Cap.{3}{4}][{5}]",
|
2018-08-29 09:21:07 +00:00
|
|
|
|
result.SeriesName, seasonText, quality, episodeText, episodeToText, audioQuality);
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Match matchClassic = _titleClassicRegex.Match(title);
|
|
|
|
|
if (matchClassic.Success)
|
|
|
|
|
{
|
2018-10-20 05:48:53 +00:00
|
|
|
|
result.Season = matchClassic.Groups[2].Success ? (int?)int.Parse(matchClassic.Groups[2].Value) : null;
|
|
|
|
|
result.Episode = matchClassic.Groups[3].Success ? (int?)int.Parse(matchClassic.Groups[3].Value) : null;
|
|
|
|
|
result.EpisodeTo = matchClassic.Groups[6].Success ? (int?)int.Parse(matchClassic.Groups[6].Value) : null;
|
|
|
|
|
if (matchClassic.Groups[1].Success)
|
|
|
|
|
quality = matchClassic.Groups[1].Value;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.Title = title;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (releaseType == ReleaseType.TV)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(quality) && (quality.Contains("720") || quality.Contains("1080")))
|
|
|
|
|
result.Category = new List<int> { TorznabCatType.TVHD.ID };
|
|
|
|
|
else
|
|
|
|
|
result.Category = new List<int> { TorznabCatType.TV.ID };
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result.Title = title;
|
|
|
|
|
result.Category = new List<int> { TorznabCatType.Movies.ID };
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 14:53:15 +00:00
|
|
|
|
if (size > 0)
|
|
|
|
|
result.Size = size;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
result.Link = new Uri(detailsUrl);
|
2018-07-03 14:17:16 +00:00
|
|
|
|
result.Guid = result.Link;
|
2018-05-12 01:55:24 +00:00
|
|
|
|
result.PublishDate = publishDate;
|
|
|
|
|
result.Seeders = 1;
|
|
|
|
|
result.Peers = 1;
|
|
|
|
|
|
2018-10-20 05:48:53 +00:00
|
|
|
|
result.Title = FixedTitle(result, quality, language);
|
2018-07-02 10:56:53 +00:00
|
|
|
|
|
2018-05-12 01:55:24 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
2018-07-02 10:56:53 +00:00
|
|
|
|
|
2018-10-20 05:48:53 +00:00
|
|
|
|
private string FixedTitle(NewpctRelease release, string quality, string language)
|
2018-07-02 10:56:53 +00:00
|
|
|
|
{
|
2018-08-29 09:21:07 +00:00
|
|
|
|
if (String.IsNullOrEmpty(release.SeriesName))
|
2018-07-03 09:01:08 +00:00
|
|
|
|
{
|
2018-08-29 09:21:07 +00:00
|
|
|
|
release.SeriesName = release.Title;
|
2018-11-19 10:50:24 +00:00
|
|
|
|
if (release.NewpctReleaseType == ReleaseType.TV && release.SeriesName.Contains("-"))
|
|
|
|
|
release.SeriesName = release.Title.Substring(0, release.SeriesName.IndexOf('-') - 1);
|
2018-07-03 09:01:08 +00:00
|
|
|
|
}
|
2018-10-20 05:48:53 +00:00
|
|
|
|
|
2018-08-29 09:21:07 +00:00
|
|
|
|
var titleParts = new List<string>();
|
2018-10-20 05:48:53 +00:00
|
|
|
|
|
2018-08-29 09:21:07 +00:00
|
|
|
|
titleParts.Add(release.SeriesName);
|
2018-10-20 05:48:53 +00:00
|
|
|
|
|
2018-08-29 09:21:07 +00:00
|
|
|
|
if (release.NewpctReleaseType == ReleaseType.TV)
|
2018-07-03 09:01:08 +00:00
|
|
|
|
{
|
2018-11-19 10:50:24 +00:00
|
|
|
|
if (String.IsNullOrEmpty(quality))
|
|
|
|
|
quality = "HDTV";
|
|
|
|
|
|
2018-08-29 09:21:07 +00:00
|
|
|
|
var seasonAndEpisode = "S" + release.Season.ToString().PadLeft(2, '0');
|
|
|
|
|
seasonAndEpisode += "E" + release.Episode.ToString().PadLeft(2, '0');
|
|
|
|
|
if (release.EpisodeTo != release.Episode && release.EpisodeTo != null && release.EpisodeTo != 0)
|
|
|
|
|
{
|
|
|
|
|
seasonAndEpisode += "-" + release.EpisodeTo.ToString().PadLeft(2, '0');
|
|
|
|
|
}
|
|
|
|
|
titleParts.Add(seasonAndEpisode);
|
2018-07-03 09:01:08 +00:00
|
|
|
|
}
|
2018-10-20 05:48:53 +00:00
|
|
|
|
|
2018-11-19 10:50:24 +00:00
|
|
|
|
if (!string.IsNullOrEmpty(quality) && !release.SeriesName.Contains(quality))
|
2018-10-20 05:48:53 +00:00
|
|
|
|
{
|
|
|
|
|
titleParts.Add(quality);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(language) && !release.SeriesName.Contains(language))
|
|
|
|
|
{
|
|
|
|
|
titleParts.Add(language);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-19 10:50:24 +00:00
|
|
|
|
if (release.Title.ToLower().Contains("espa\u00F1ol") ||
|
|
|
|
|
release.Title.ToLower().Contains("espanol") ||
|
|
|
|
|
release.Title.ToLower().Contains("castellano") ||
|
|
|
|
|
release.Title.ToLower().EndsWith("espa"))
|
2018-07-02 10:56:53 +00:00
|
|
|
|
{
|
|
|
|
|
titleParts.Add("Spanish");
|
|
|
|
|
}
|
2018-10-20 05:48:53 +00:00
|
|
|
|
|
|
|
|
|
string result = String.Join(".", titleParts);
|
|
|
|
|
|
|
|
|
|
result = Regex.Replace(result, @"[\[\]]+", ".");
|
2018-11-19 10:50:24 +00:00
|
|
|
|
result = Regex.Replace(result, @"\.[ \.]*\.", ".");
|
2018-10-20 05:48:53 +00:00
|
|
|
|
|
|
|
|
|
return result;
|
2018-07-02 10:56:53 +00:00
|
|
|
|
}
|
2018-05-12 01:55:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|