mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-16 17:04:08 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
301cdc6c37 | ||
![]() |
4ebd1c4580 | ||
![]() |
8a7a07df44 | ||
![]() |
9ec2f6716a | ||
![]() |
7cb8da1495 | ||
![]() |
1e62e612fb | ||
![]() |
75405acd77 | ||
![]() |
8e96a9cab1 | ||
![]() |
4cca729e2f | ||
![]() |
c7e9783350 | ||
![]() |
bdb19e09ff |
@@ -40,10 +40,11 @@ We were previously focused on TV but are working on extending searches to allow
|
||||
* [NextGen](https://nxtgn.org/)
|
||||
* [pretome](https://pretome.info)
|
||||
* [PrivateHD](https://privatehd.to/)
|
||||
* [RARGB](https://rarbg.to/)
|
||||
* [RARBG](https://rarbg.to/)
|
||||
* [RuTor](http://rutor.org/)
|
||||
* [SceneAccess](https://sceneaccess.eu/login)
|
||||
* [SceneTime](https://www.scenetime.com/)
|
||||
* [Shazbat](www.shazbat.tv/login)
|
||||
* [ShowRSS](https://showrss.info/)
|
||||
* [Strike](https://getstrike.net/)
|
||||
* [T411](http://www.t411.io/)
|
||||
|
@@ -367,7 +367,7 @@ function bindUIButtons() {
|
||||
var count = 0;
|
||||
this.api().columns().every(function () {
|
||||
count++;
|
||||
if (count === 5 || count === 7) {
|
||||
if (count === 5 || count === 9) {
|
||||
var column = this;
|
||||
var select = $('<select><option value=""></option></select>')
|
||||
.appendTo($(column.footer()).empty())
|
||||
@@ -495,7 +495,7 @@ function bindUIButtons() {
|
||||
var count = 0;
|
||||
this.api().columns().every(function () {
|
||||
count++;
|
||||
if (count === 3 || count === 5) {
|
||||
if (count === 3 || count === 7) {
|
||||
var column = this;
|
||||
var select = $('<select><option value=""></option></select>')
|
||||
.appendTo($(column.footer()).empty())
|
||||
|
@@ -169,7 +169,7 @@
|
||||
|
||||
<input class="form-control" type="text" value="{{potato_host}}" placeholder="Torznab Host" readonly="">
|
||||
{{else}}
|
||||
<input class="form-control" type="text" value="Not availible" placeholder="Torznab Host" readonly="">
|
||||
<input class="form-control" type="text" value="Not available" placeholder="Torznab Host" readonly="">
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -452,4 +452,4 @@
|
||||
|
||||
<script src="/custom.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
BIN
src/Jackett/Content/logos/broadcastthenet.png
Normal file
BIN
src/Jackett/Content/logos/broadcastthenet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
src/Jackett/Content/logos/shazbat.png
Normal file
BIN
src/Jackett/Content/logos/shazbat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
@@ -24,13 +24,15 @@ namespace Jackett
|
||||
public string Referer { get; private set; }
|
||||
public HttpMethod Method { get; private set; }
|
||||
public IEnumerable<KeyValuePair<string, string>> PostData { get; set; }
|
||||
public string RawPOSTDdata { get; set;}
|
||||
|
||||
public CurlRequest(HttpMethod method, string url, string cookies = null, string referer = null)
|
||||
public CurlRequest(HttpMethod method, string url, string cookies = null, string referer = null, string rawPOSTData = null)
|
||||
{
|
||||
Method = method;
|
||||
Url = url;
|
||||
Cookies = cookies;
|
||||
Referer = referer;
|
||||
RawPOSTDdata = rawPOSTData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,10 +59,11 @@ namespace Jackett
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<CurlResponse> PostAsync(string url, IEnumerable<KeyValuePair<string, string>> formData, string cookies = null, string referer = null)
|
||||
public static async Task<CurlResponse> PostAsync(string url, IEnumerable<KeyValuePair<string, string>> formData, string cookies = null, string referer = null, string rawPostData =null)
|
||||
{
|
||||
var curlRequest = new CurlRequest(HttpMethod.Post, url, cookies, referer);
|
||||
curlRequest.PostData = formData;
|
||||
curlRequest.RawPOSTDdata = rawPostData;
|
||||
var result = await PerformCurlAsync(curlRequest);
|
||||
return result;
|
||||
}
|
||||
@@ -108,10 +111,19 @@ namespace Jackett
|
||||
|
||||
if (curlRequest.Method == HttpMethod.Post)
|
||||
{
|
||||
easy.Post = true;
|
||||
var postString = StringUtil.PostDataFromDict(curlRequest.PostData);
|
||||
easy.PostFields = postString;
|
||||
easy.PostFieldSize = Encoding.UTF8.GetByteCount(postString);
|
||||
if (!string.IsNullOrEmpty(curlRequest.RawPOSTDdata))
|
||||
{
|
||||
easy.Post = true;
|
||||
easy.PostFields = curlRequest.RawPOSTDdata;
|
||||
easy.PostFieldSize = Encoding.UTF8.GetByteCount(curlRequest.RawPOSTDdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
easy.Post = true;
|
||||
var postString = StringUtil.PostDataFromDict(curlRequest.PostData);
|
||||
easy.PostFields = postString;
|
||||
easy.PostFieldSize = Encoding.UTF8.GetByteCount(postString);
|
||||
}
|
||||
}
|
||||
|
||||
if (Startup.DoSSLFix == true)
|
||||
@@ -142,6 +154,7 @@ namespace Jackett
|
||||
var headerCount = 0;
|
||||
HttpStatusCode status = HttpStatusCode.InternalServerError;
|
||||
var cookieBuilder = new StringBuilder();
|
||||
var cookies = new List<Tuple<string, string>>();
|
||||
foreach (var headerPart in headerParts)
|
||||
{
|
||||
if (headerCount == 0)
|
||||
@@ -162,7 +175,10 @@ namespace Jackett
|
||||
|
||||
if (key == "set-cookie")
|
||||
{
|
||||
cookieBuilder.AppendFormat("{0} ", value.Substring(0, value.IndexOf(';') + 1));
|
||||
var nameSplit = value.IndexOf('=');
|
||||
if (nameSplit > -1) {
|
||||
cookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') + 1)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -174,8 +190,13 @@ namespace Jackett
|
||||
headerCount++;
|
||||
}
|
||||
|
||||
foreach (var cookieGroup in cookies.GroupBy(c => c.Item1))
|
||||
{
|
||||
cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2);
|
||||
}
|
||||
|
||||
var contentBytes = Combine(contentBuffers.ToArray());
|
||||
var curlResponse = new CurlResponse(headers, contentBytes, status, cookieBuilder.ToString().TrimEnd());
|
||||
var curlResponse = new CurlResponse(headers, contentBytes, status, cookieBuilder.ToString().Trim());
|
||||
return curlResponse;
|
||||
}
|
||||
}
|
||||
|
@@ -1,393 +1,394 @@
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class AnimeBytes : BaseIndexer, IIndexer
|
||||
{
|
||||
private string LoginUrl { get { return SiteLink + "user/login"; } }
|
||||
private string SearchUrl { get { return SiteLink + "torrents.php?"; } }
|
||||
public bool AllowRaws { get { return configData.IncludeRaw.Value; } }
|
||||
|
||||
new ConfigurationDataAnimeBytes configData
|
||||
{
|
||||
get { return (ConfigurationDataAnimeBytes)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps)
|
||||
: base(name: "AnimeBytes",
|
||||
link: "https://animebytes.tv/",
|
||||
description: "Powered by Tentacles",
|
||||
manager: i,
|
||||
client: client,
|
||||
caps: new TorznabCapabilities(TorznabCatType.TVAnime,
|
||||
TorznabCatType.Movies,
|
||||
TorznabCatType.BooksComics,
|
||||
TorznabCatType.ConsolePSP,
|
||||
TorznabCatType.ConsoleOther,
|
||||
TorznabCatType.PCGames),
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataAnimeBytes())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
|
||||
lock (cache)
|
||||
{
|
||||
cache.Clear();
|
||||
}
|
||||
|
||||
// Get the login form as we need the CSRF Token
|
||||
var loginPage = await webclient.GetString(new Utils.Clients.WebRequest()
|
||||
{
|
||||
Url = LoginUrl
|
||||
});
|
||||
|
||||
CQ loginPageDom = loginPage.Content;
|
||||
var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last();
|
||||
|
||||
// Build login form
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "csrf_token", csrfToken.Attr("value") },
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value },
|
||||
{ "keeplogged_sent", "true" },
|
||||
{ "keeplogged", "on" },
|
||||
{ "login", "Log In!" }
|
||||
};
|
||||
|
||||
// Do the login
|
||||
var request = new Utils.Clients.WebRequest()
|
||||
{
|
||||
Cookies = loginPage.Cookies,
|
||||
PostData = pairs,
|
||||
Referer = LoginUrl,
|
||||
Type = RequestType.POST,
|
||||
Url = LoginUrl
|
||||
};
|
||||
var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null);
|
||||
|
||||
// Follow the redirect
|
||||
await FollowIfRedirect(response, request.Url, SearchUrl);
|
||||
|
||||
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () =>
|
||||
{
|
||||
// Their login page appears to be broken and just gives a 500 error.
|
||||
throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
// Override to load legacy config format
|
||||
public override void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
if (jsonConfig is JObject)
|
||||
{
|
||||
configData.CookieHeader.Value = jsonConfig.Value<string>("cookies");
|
||||
configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws");
|
||||
SaveConfig();
|
||||
IsConfigured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
base.LoadFromSavedConfiguration(jsonConfig);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
// The result list
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
foreach (var result in await GetResults(query.SanitizedSearchTerm))
|
||||
{
|
||||
releases.Add(result);
|
||||
}
|
||||
|
||||
return releases.ToArray();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> GetResults(string searchTerm)
|
||||
{
|
||||
var cleanSearchTerm = HttpUtility.UrlEncode(searchTerm);
|
||||
|
||||
// This tracker only deals with full seasons so chop off the episode/season number if we have it D:
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
var splitindex = searchTerm.LastIndexOf(' ');
|
||||
if (splitindex > -1)
|
||||
searchTerm = searchTerm.Substring(0, splitindex);
|
||||
}
|
||||
|
||||
// The result list
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
// Check cache first so we don't query the server for each episode when searching for each episode in a series.
|
||||
lock (cache)
|
||||
{
|
||||
// Remove old cache items
|
||||
CleanCache();
|
||||
|
||||
var cachedResult = cache.Where(i => i.Query == searchTerm).FirstOrDefault();
|
||||
if (cachedResult != null)
|
||||
return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray();
|
||||
}
|
||||
|
||||
var queryUrl = SearchUrl;
|
||||
// Only include the query bit if its required as hopefully the site caches the non query page
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
queryUrl += string.Format("searchstr={0}&action=advanced&search_type=title&year=&year2=&tags=&tags_type=0&sort=time_added&way=desc&hentai=2&releasegroup=&epcount=&epcount2=&artbooktitle=", cleanSearchTerm);
|
||||
}
|
||||
|
||||
// Get the content from the tracker
|
||||
var response = await RequestStringWithCookiesAndRetry(queryUrl);
|
||||
CQ dom = response.Content;
|
||||
|
||||
// Parse
|
||||
try
|
||||
{
|
||||
var releaseInfo = "S01";
|
||||
var root = dom.Find(".group_cont");
|
||||
// We may have got redirected to the series page if we have none of these
|
||||
if (root.Count() == 0)
|
||||
root = dom.Find(".torrent_table");
|
||||
|
||||
foreach (var series in root)
|
||||
{
|
||||
var seriesCq = series.Cq();
|
||||
|
||||
var synonyms = new List<string>();
|
||||
var mainTitle = seriesCq.Find(".group_title strong a").First().Text().Trim();
|
||||
|
||||
var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim();
|
||||
int yearIndex = yearStr.LastIndexOf("[");
|
||||
if (yearIndex > -1)
|
||||
yearStr = yearStr.Substring(yearIndex + 1);
|
||||
|
||||
int year = 0;
|
||||
if (!int.TryParse(yearStr, out year))
|
||||
year = DateTime.Now.Year;
|
||||
|
||||
synonyms.Add(mainTitle);
|
||||
|
||||
// If the title contains a comma then we can't use the synonyms as they are comma seperated
|
||||
if (!mainTitle.Contains(","))
|
||||
{
|
||||
var symnomnNames = string.Empty;
|
||||
foreach (var e in seriesCq.Find(".group_statbox li"))
|
||||
{
|
||||
if (e.FirstChild.InnerText == "Synonyms:")
|
||||
{
|
||||
symnomnNames = e.InnerText;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(symnomnNames))
|
||||
{
|
||||
foreach (var name in symnomnNames.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var theName = name.Trim();
|
||||
if (!theName.Contains("&#") && !string.IsNullOrWhiteSpace(theName))
|
||||
{
|
||||
synonyms.Add(theName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var title in synonyms)
|
||||
{
|
||||
var releaseRows = seriesCq.Find(".torrent_group tr");
|
||||
|
||||
// Skip the first two info rows
|
||||
for (int r = 1; r < releaseRows.Count(); r++)
|
||||
{
|
||||
var row = releaseRows.Get(r);
|
||||
var rowCq = row.Cq();
|
||||
if (rowCq.HasClass("edition_info"))
|
||||
{
|
||||
releaseInfo = rowCq.Find("td").Text();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(releaseInfo))
|
||||
{
|
||||
// Single episodes alpha - Reported that this info is missing.
|
||||
// It should self correct when availible
|
||||
break;
|
||||
}
|
||||
|
||||
releaseInfo = releaseInfo.Replace("Episode ", "");
|
||||
releaseInfo = releaseInfo.Replace("Season ", "S");
|
||||
releaseInfo = releaseInfo.Trim();
|
||||
}
|
||||
else if (rowCq.HasClass("torrent"))
|
||||
{
|
||||
var links = rowCq.Find("a");
|
||||
// Protect against format changes
|
||||
if (links.Count() != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var release = new ReleaseInfo();
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 259200;
|
||||
var downloadLink = links.Get(0);
|
||||
|
||||
// We dont know this so try to fake based on the release year
|
||||
release.PublishDate = new DateTime(year, 1, 1);
|
||||
release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1);
|
||||
|
||||
var infoLink = links.Get(1);
|
||||
release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href"));
|
||||
release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name.
|
||||
release.Link = new Uri(downloadLink.Attributes.GetAttribute("href"), UriKind.Relative);
|
||||
|
||||
var category = seriesCq.Find("a[title=\"View Torrent\"]").Text().Trim();
|
||||
if (category == "TV Series")
|
||||
release.Category = TorznabCatType.TVAnime.ID;
|
||||
|
||||
// Ignore these categories as they'll cause hell with the matcher
|
||||
// TV Special, OVA, ONA, DVD Special, BD Special
|
||||
|
||||
if (category == "Movie")
|
||||
release.Category = TorznabCatType.Movies.ID;
|
||||
|
||||
if (category == "Manga" || category == "Oneshot" || category == "Anthology" || category == "Manhwa" || category == "Manhua" || category == "Light Novel")
|
||||
release.Category = TorznabCatType.BooksComics.ID;
|
||||
|
||||
if (category == "Novel" || category == "Artbook")
|
||||
release.Category = TorznabCatType.BooksComics.ID;
|
||||
|
||||
if (category == "Game" || category == "Visual Novel")
|
||||
{
|
||||
var description = rowCq.Find(".torrent_properties a:eq(1)").Text();
|
||||
if (description.Contains(" PSP "))
|
||||
release.Category = TorznabCatType.ConsolePSP.ID;
|
||||
if (description.Contains("PSX"))
|
||||
release.Category = TorznabCatType.ConsoleOther.ID;
|
||||
if (description.Contains(" NES "))
|
||||
release.Category = TorznabCatType.ConsoleOther.ID;
|
||||
if (description.Contains(" PC "))
|
||||
release.Category = TorznabCatType.PCGames.ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// We dont actually have a release name >.> so try to create one
|
||||
var releaseTags = infoLink.InnerText.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
for (int i = releaseTags.Count - 1; i >= 0; i--)
|
||||
{
|
||||
releaseTags[i] = releaseTags[i].Trim();
|
||||
if (string.IsNullOrWhiteSpace(releaseTags[i]))
|
||||
releaseTags.RemoveAt(i);
|
||||
}
|
||||
|
||||
var group = releaseTags.Last();
|
||||
if (group.Contains("(") && group.Contains(")"))
|
||||
{
|
||||
// Skip raws if set
|
||||
if (group.ToLowerInvariant().StartsWith("raw") && !AllowRaws)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var start = group.IndexOf("(");
|
||||
group = "[" + group.Substring(start + 1, (group.IndexOf(")") - 1) - start) + "] ";
|
||||
}
|
||||
else
|
||||
{
|
||||
group = string.Empty;
|
||||
}
|
||||
|
||||
var infoString = "";
|
||||
|
||||
for (int i = 0; i + 1 < releaseTags.Count(); i++)
|
||||
{
|
||||
if (releaseTags[i] == "Raw" && !AllowRaws)
|
||||
continue;
|
||||
infoString += "[" + releaseTags[i] + "]";
|
||||
}
|
||||
|
||||
if (category == "Movie")
|
||||
{
|
||||
release.Title = string.Format("{0} {1} {2}{3}", title, year, group, infoString);
|
||||
}
|
||||
else
|
||||
{
|
||||
release.Title = string.Format("{0}{1} {2} {3}", group, title, releaseInfo, infoString);
|
||||
}
|
||||
release.Description = title;
|
||||
|
||||
var size = rowCq.Find(".torrent_size");
|
||||
if (size.Count() > 0)
|
||||
{
|
||||
release.Size = ReleaseInfo.GetBytes(size.First().Text());
|
||||
}
|
||||
|
||||
// Additional 5 hours per GB
|
||||
release.MinimumSeedTime += (release.Size / 1000000000) * 18000;
|
||||
|
||||
// Peer info
|
||||
release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text());
|
||||
release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text());
|
||||
|
||||
if (release.Category != 0)
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(response.Content, ex);
|
||||
}
|
||||
|
||||
// Add to the cache
|
||||
lock (cache)
|
||||
{
|
||||
cache.Add(new CachedQueryResult(searchTerm, releases));
|
||||
}
|
||||
|
||||
return releases.Select(s => (ReleaseInfo)s.Clone());
|
||||
}
|
||||
|
||||
|
||||
public async override Task<byte[]> Download(Uri link)
|
||||
{
|
||||
// The urls for this tracker are quite long so append the domain after the incoming request.
|
||||
var response = await webclient.GetBytes(new Utils.Clients.WebRequest()
|
||||
{
|
||||
Url = SiteLink + link.ToString(),
|
||||
Cookies = CookieHeader
|
||||
});
|
||||
|
||||
return response.Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using Jackett.Models.IndexerConfig.Bespoke;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class AnimeBytes : BaseIndexer, IIndexer
|
||||
{
|
||||
private string LoginUrl { get { return SiteLink + "user/login"; } }
|
||||
private string SearchUrl { get { return SiteLink + "torrents.php?"; } }
|
||||
public bool AllowRaws { get { return configData.IncludeRaw.Value; } }
|
||||
|
||||
new ConfigurationDataAnimeBytes configData
|
||||
{
|
||||
get { return (ConfigurationDataAnimeBytes)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps)
|
||||
: base(name: "AnimeBytes",
|
||||
link: "https://animebytes.tv/",
|
||||
description: "Powered by Tentacles",
|
||||
manager: i,
|
||||
client: client,
|
||||
caps: new TorznabCapabilities(TorznabCatType.TVAnime,
|
||||
TorznabCatType.Movies,
|
||||
TorznabCatType.BooksComics,
|
||||
TorznabCatType.ConsolePSP,
|
||||
TorznabCatType.ConsoleOther,
|
||||
TorznabCatType.PCGames),
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataAnimeBytes())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
|
||||
lock (cache)
|
||||
{
|
||||
cache.Clear();
|
||||
}
|
||||
|
||||
// Get the login form as we need the CSRF Token
|
||||
var loginPage = await webclient.GetString(new Utils.Clients.WebRequest()
|
||||
{
|
||||
Url = LoginUrl
|
||||
});
|
||||
|
||||
CQ loginPageDom = loginPage.Content;
|
||||
var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last();
|
||||
|
||||
// Build login form
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "csrf_token", csrfToken.Attr("value") },
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value },
|
||||
{ "keeplogged_sent", "true" },
|
||||
{ "keeplogged", "on" },
|
||||
{ "login", "Log In!" }
|
||||
};
|
||||
|
||||
// Do the login
|
||||
var request = new Utils.Clients.WebRequest()
|
||||
{
|
||||
Cookies = loginPage.Cookies,
|
||||
PostData = pairs,
|
||||
Referer = LoginUrl,
|
||||
Type = RequestType.POST,
|
||||
Url = LoginUrl
|
||||
};
|
||||
var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null);
|
||||
|
||||
// Follow the redirect
|
||||
await FollowIfRedirect(response, request.Url, SearchUrl);
|
||||
|
||||
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () =>
|
||||
{
|
||||
// Their login page appears to be broken and just gives a 500 error.
|
||||
throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
// Override to load legacy config format
|
||||
public override void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
if (jsonConfig is JObject)
|
||||
{
|
||||
configData.CookieHeader.Value = jsonConfig.Value<string>("cookies");
|
||||
configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws");
|
||||
SaveConfig();
|
||||
IsConfigured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
base.LoadFromSavedConfiguration(jsonConfig);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
// The result list
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
foreach (var result in await GetResults(query.SanitizedSearchTerm))
|
||||
{
|
||||
releases.Add(result);
|
||||
}
|
||||
|
||||
return releases.ToArray();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> GetResults(string searchTerm)
|
||||
{
|
||||
var cleanSearchTerm = HttpUtility.UrlEncode(searchTerm);
|
||||
|
||||
// This tracker only deals with full seasons so chop off the episode/season number if we have it D:
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
var splitindex = searchTerm.LastIndexOf(' ');
|
||||
if (splitindex > -1)
|
||||
searchTerm = searchTerm.Substring(0, splitindex);
|
||||
}
|
||||
|
||||
// The result list
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
// Check cache first so we don't query the server for each episode when searching for each episode in a series.
|
||||
lock (cache)
|
||||
{
|
||||
// Remove old cache items
|
||||
CleanCache();
|
||||
|
||||
var cachedResult = cache.Where(i => i.Query == searchTerm).FirstOrDefault();
|
||||
if (cachedResult != null)
|
||||
return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray();
|
||||
}
|
||||
|
||||
var queryUrl = SearchUrl;
|
||||
// Only include the query bit if its required as hopefully the site caches the non query page
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
queryUrl += string.Format("searchstr={0}&action=advanced&search_type=title&year=&year2=&tags=&tags_type=0&sort=time_added&way=desc&hentai=2&releasegroup=&epcount=&epcount2=&artbooktitle=", cleanSearchTerm);
|
||||
}
|
||||
|
||||
// Get the content from the tracker
|
||||
var response = await RequestStringWithCookiesAndRetry(queryUrl);
|
||||
CQ dom = response.Content;
|
||||
|
||||
// Parse
|
||||
try
|
||||
{
|
||||
var releaseInfo = "S01";
|
||||
var root = dom.Find(".group_cont");
|
||||
// We may have got redirected to the series page if we have none of these
|
||||
if (root.Count() == 0)
|
||||
root = dom.Find(".torrent_table");
|
||||
|
||||
foreach (var series in root)
|
||||
{
|
||||
var seriesCq = series.Cq();
|
||||
|
||||
var synonyms = new List<string>();
|
||||
var mainTitle = seriesCq.Find(".group_title strong a").First().Text().Trim();
|
||||
|
||||
var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim();
|
||||
int yearIndex = yearStr.LastIndexOf("[");
|
||||
if (yearIndex > -1)
|
||||
yearStr = yearStr.Substring(yearIndex + 1);
|
||||
|
||||
int year = 0;
|
||||
if (!int.TryParse(yearStr, out year))
|
||||
year = DateTime.Now.Year;
|
||||
|
||||
synonyms.Add(mainTitle);
|
||||
|
||||
// If the title contains a comma then we can't use the synonyms as they are comma seperated
|
||||
if (!mainTitle.Contains(","))
|
||||
{
|
||||
var symnomnNames = string.Empty;
|
||||
foreach (var e in seriesCq.Find(".group_statbox li"))
|
||||
{
|
||||
if (e.FirstChild.InnerText == "Synonyms:")
|
||||
{
|
||||
symnomnNames = e.InnerText;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(symnomnNames))
|
||||
{
|
||||
foreach (var name in symnomnNames.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var theName = name.Trim();
|
||||
if (!theName.Contains("&#") && !string.IsNullOrWhiteSpace(theName))
|
||||
{
|
||||
synonyms.Add(theName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var title in synonyms)
|
||||
{
|
||||
var releaseRows = seriesCq.Find(".torrent_group tr");
|
||||
|
||||
// Skip the first two info rows
|
||||
for (int r = 1; r < releaseRows.Count(); r++)
|
||||
{
|
||||
var row = releaseRows.Get(r);
|
||||
var rowCq = row.Cq();
|
||||
if (rowCq.HasClass("edition_info"))
|
||||
{
|
||||
releaseInfo = rowCq.Find("td").Text();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(releaseInfo))
|
||||
{
|
||||
// Single episodes alpha - Reported that this info is missing.
|
||||
// It should self correct when availible
|
||||
break;
|
||||
}
|
||||
|
||||
releaseInfo = releaseInfo.Replace("Episode ", "");
|
||||
releaseInfo = releaseInfo.Replace("Season ", "S");
|
||||
releaseInfo = releaseInfo.Trim();
|
||||
}
|
||||
else if (rowCq.HasClass("torrent"))
|
||||
{
|
||||
var links = rowCq.Find("a");
|
||||
// Protect against format changes
|
||||
if (links.Count() != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var release = new ReleaseInfo();
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 259200;
|
||||
var downloadLink = links.Get(0);
|
||||
|
||||
// We dont know this so try to fake based on the release year
|
||||
release.PublishDate = new DateTime(year, 1, 1);
|
||||
release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1);
|
||||
|
||||
var infoLink = links.Get(1);
|
||||
release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href"));
|
||||
release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name.
|
||||
release.Link = new Uri(downloadLink.Attributes.GetAttribute("href"), UriKind.Relative);
|
||||
|
||||
var category = seriesCq.Find("a[title=\"View Torrent\"]").Text().Trim();
|
||||
if (category == "TV Series")
|
||||
release.Category = TorznabCatType.TVAnime.ID;
|
||||
|
||||
// Ignore these categories as they'll cause hell with the matcher
|
||||
// TV Special, OVA, ONA, DVD Special, BD Special
|
||||
|
||||
if (category == "Movie")
|
||||
release.Category = TorznabCatType.Movies.ID;
|
||||
|
||||
if (category == "Manga" || category == "Oneshot" || category == "Anthology" || category == "Manhwa" || category == "Manhua" || category == "Light Novel")
|
||||
release.Category = TorznabCatType.BooksComics.ID;
|
||||
|
||||
if (category == "Novel" || category == "Artbook")
|
||||
release.Category = TorznabCatType.BooksComics.ID;
|
||||
|
||||
if (category == "Game" || category == "Visual Novel")
|
||||
{
|
||||
var description = rowCq.Find(".torrent_properties a:eq(1)").Text();
|
||||
if (description.Contains(" PSP "))
|
||||
release.Category = TorznabCatType.ConsolePSP.ID;
|
||||
if (description.Contains("PSX"))
|
||||
release.Category = TorznabCatType.ConsoleOther.ID;
|
||||
if (description.Contains(" NES "))
|
||||
release.Category = TorznabCatType.ConsoleOther.ID;
|
||||
if (description.Contains(" PC "))
|
||||
release.Category = TorznabCatType.PCGames.ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// We dont actually have a release name >.> so try to create one
|
||||
var releaseTags = infoLink.InnerText.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
for (int i = releaseTags.Count - 1; i >= 0; i--)
|
||||
{
|
||||
releaseTags[i] = releaseTags[i].Trim();
|
||||
if (string.IsNullOrWhiteSpace(releaseTags[i]))
|
||||
releaseTags.RemoveAt(i);
|
||||
}
|
||||
|
||||
var group = releaseTags.Last();
|
||||
if (group.Contains("(") && group.Contains(")"))
|
||||
{
|
||||
// Skip raws if set
|
||||
if (group.ToLowerInvariant().StartsWith("raw") && !AllowRaws)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var start = group.IndexOf("(");
|
||||
group = "[" + group.Substring(start + 1, (group.IndexOf(")") - 1) - start) + "] ";
|
||||
}
|
||||
else
|
||||
{
|
||||
group = string.Empty;
|
||||
}
|
||||
|
||||
var infoString = "";
|
||||
|
||||
for (int i = 0; i + 1 < releaseTags.Count(); i++)
|
||||
{
|
||||
if (releaseTags[i] == "Raw" && !AllowRaws)
|
||||
continue;
|
||||
infoString += "[" + releaseTags[i] + "]";
|
||||
}
|
||||
|
||||
if (category == "Movie")
|
||||
{
|
||||
release.Title = string.Format("{0} {1} {2}{3}", title, year, group, infoString);
|
||||
}
|
||||
else
|
||||
{
|
||||
release.Title = string.Format("{0}{1} {2} {3}", group, title, releaseInfo, infoString);
|
||||
}
|
||||
release.Description = title;
|
||||
|
||||
var size = rowCq.Find(".torrent_size");
|
||||
if (size.Count() > 0)
|
||||
{
|
||||
release.Size = ReleaseInfo.GetBytes(size.First().Text());
|
||||
}
|
||||
|
||||
// Additional 5 hours per GB
|
||||
release.MinimumSeedTime += (release.Size / 1000000000) * 18000;
|
||||
|
||||
// Peer info
|
||||
release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text());
|
||||
release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text());
|
||||
|
||||
if (release.Category != 0)
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(response.Content, ex);
|
||||
}
|
||||
|
||||
// Add to the cache
|
||||
lock (cache)
|
||||
{
|
||||
cache.Add(new CachedQueryResult(searchTerm, releases));
|
||||
}
|
||||
|
||||
return releases.Select(s => (ReleaseInfo)s.Clone());
|
||||
}
|
||||
|
||||
|
||||
public async override Task<byte[]> Download(Uri link)
|
||||
{
|
||||
// The urls for this tracker are quite long so append the domain after the incoming request.
|
||||
var response = await webclient.GetBytes(new Utils.Clients.WebRequest()
|
||||
{
|
||||
Url = SiteLink + link.ToString(),
|
||||
Cookies = CookieHeader
|
||||
});
|
||||
|
||||
return response.Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -83,6 +83,11 @@ namespace Jackett.Indexers
|
||||
|
||||
public Uri UncleanLink(Uri link)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(downloadUrlBase))
|
||||
{
|
||||
return link;
|
||||
}
|
||||
|
||||
if (link.ToString().StartsWith(downloadUrlBase))
|
||||
{
|
||||
return link;
|
||||
@@ -306,26 +311,32 @@ namespace Jackett.Indexers
|
||||
return await webclient.GetBytes(request);
|
||||
}
|
||||
|
||||
protected async Task<WebClientStringResult> PostDataWithCookies(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null)
|
||||
protected async Task<WebClientStringResult> PostDataWithCookies(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null, string rawbody = null, bool? emulateBrowser = null)
|
||||
{
|
||||
var request = new Utils.Clients.WebRequest()
|
||||
{
|
||||
Url = url,
|
||||
Type = RequestType.POST,
|
||||
Cookies = cookieOverride ?? CookieHeader,
|
||||
PostData = data
|
||||
PostData = data,
|
||||
Referer = referer,
|
||||
Headers = headers,
|
||||
RawBody = rawbody
|
||||
};
|
||||
|
||||
if (emulateBrowser.HasValue)
|
||||
request.EmulateBrowser = emulateBrowser.Value;
|
||||
return await webclient.GetString(request);
|
||||
}
|
||||
|
||||
protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null)
|
||||
protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null, string rawbody = null, bool? emulateBrowser = null)
|
||||
{
|
||||
Exception lastException = null;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await PostDataWithCookies(url, data, cookieOverride);
|
||||
return await PostDataWithCookies(url, data, cookieOverride, referer, headers, rawbody, emulateBrowser);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
174
src/Jackett/Indexers/BroadcastTheNet.cs
Normal file
174
src/Jackett/Indexers/BroadcastTheNet.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Dynamic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class BroadcastTheNet : BaseIndexer, IIndexer
|
||||
{
|
||||
string APIBASE = "http://api.btnapps.net/";
|
||||
|
||||
new ConfigurationDataAPIKey configData
|
||||
{
|
||||
get { return (ConfigurationDataAPIKey)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public BroadcastTheNet(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "BroadcastTheNet",
|
||||
description: "Needs no description..",
|
||||
link: "https://broadcasthe.net/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataAPIKey())
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
|
||||
IsConfigured = false;
|
||||
try
|
||||
{
|
||||
var results = await PerformQuery(new TorznabQuery());
|
||||
if (results.Count() == 0)
|
||||
throw new Exception("Testing returned no results!");
|
||||
IsConfigured = true;
|
||||
SaveConfig();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new ExceptionWithConfigData(e.Message, configData);
|
||||
}
|
||||
|
||||
return IndexerConfigurationStatus.Completed;
|
||||
}
|
||||
|
||||
|
||||
private string JsonRPCRequest(string method, JArray parameters)
|
||||
{
|
||||
dynamic request = new JObject();
|
||||
request["jsonrpc"] = "2.0";
|
||||
request["method"] = method;
|
||||
request["params"] = parameters;
|
||||
request["id"] = Guid.NewGuid().ToString().Substring(0, 8);
|
||||
return request.ToString();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var searchString = query.GetQueryString();
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
var parameters = new JArray();
|
||||
parameters.Add(new JValue(configData.Key.Value));
|
||||
parameters.Add(new JValue(searchString.Trim()));
|
||||
parameters.Add(new JValue(100));
|
||||
parameters.Add(new JValue(0));
|
||||
var response = await PostDataWithCookiesAndRetry(APIBASE, null, null, null, new Dictionary<string, string>()
|
||||
{
|
||||
{ "Accept", "application/json-rpc, application/json"},
|
||||
{"Content-Type", "application/json-rpc"}
|
||||
}, JsonRPCRequest("getTorrents", parameters),false);
|
||||
|
||||
try
|
||||
{
|
||||
var btnResponse = JsonConvert.DeserializeObject<BTNRPCResponse>(response.Content);
|
||||
|
||||
if (btnResponse != null && btnResponse.Result != null)
|
||||
{
|
||||
foreach (var itemKey in btnResponse.Result.Torrents)
|
||||
{
|
||||
var btnResult = itemKey.Value;
|
||||
var item = new ReleaseInfo();
|
||||
if (!string.IsNullOrEmpty(btnResult.SeriesBanner))
|
||||
item.BannerUrl = new Uri(btnResult.SeriesBanner);
|
||||
item.Category = TorznabCatType.TV.ID;
|
||||
item.Comments = new Uri($"https://broadcasthe.net/torrents.php?id={btnResult.GroupID}&torrentid={btnResult.TorrentID}");
|
||||
item.Description = btnResult.ReleaseName;
|
||||
item.Guid = new Uri(btnResult.DownloadURL);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.ImdbID))
|
||||
item.Imdb = ParseUtil.CoerceLong(btnResult.ImdbID);
|
||||
item.Link = new Uri(btnResult.DownloadURL);
|
||||
item.MinimumRatio = 1;
|
||||
item.PublishDate = DateTimeUtil.UnixTimestampToDateTime(btnResult.Time);
|
||||
item.RageID = btnResult.TvrageID;
|
||||
item.Seeders = btnResult.Seeders;
|
||||
item.Peers = btnResult.Seeders + btnResult.Leechers;
|
||||
item.Size = btnResult.Size;
|
||||
item.TVDBId = btnResult.TvdbID;
|
||||
item.Title = btnResult.ReleaseName;
|
||||
releases.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(response.Content, ex);
|
||||
}
|
||||
return releases;
|
||||
}
|
||||
|
||||
|
||||
public class BTNRPCResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public BTNResultPage Result { get; set; }
|
||||
}
|
||||
|
||||
public class BTNResultPage
|
||||
{
|
||||
public Dictionary<int, BTNResultItem> Torrents { get; set; }
|
||||
}
|
||||
|
||||
public class BTNResultItem
|
||||
{
|
||||
public int TorrentID { get; set; }
|
||||
public string DownloadURL { get; set; }
|
||||
public string GroupName { get; set; }
|
||||
public int GroupID { get; set; }
|
||||
public int SeriesID { get; set; }
|
||||
public string Series { get; set; }
|
||||
public string SeriesBanner { get; set; }
|
||||
public string SeriesPoster { get; set; }
|
||||
public string YoutubeTrailer { get; set; }
|
||||
public string Category { get; set; }
|
||||
public int? Snatched { get; set; }
|
||||
public int? Seeders { get; set; }
|
||||
public int? Leechers { get; set; }
|
||||
public string Source { get; set; }
|
||||
public string Container { get; set; }
|
||||
public string Codec { get; set; }
|
||||
public string Resolution { get; set; }
|
||||
public string Origin { get; set; }
|
||||
public string ReleaseName { get; set; }
|
||||
public long Size { get; set; }
|
||||
public long Time { get; set; }
|
||||
public int? TvdbID { get; set; }
|
||||
public int? TvrageID { get; set; }
|
||||
public string ImdbID { get; set; }
|
||||
public string InfoHash { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,156 +1,157 @@
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class FileList : BaseIndexer, IIndexer
|
||||
{
|
||||
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
|
||||
string BrowseUrl { get { return SiteLink + "browse.php"; } }
|
||||
|
||||
new ConfigurationDataFileList configData
|
||||
{
|
||||
get { return (ConfigurationDataFileList)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "FileList",
|
||||
description: "The best Romanian site.",
|
||||
link: "http://filelist.ro/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataFileList())
|
||||
{
|
||||
AddCategoryMapping(24, TorznabCatType.TVAnime);
|
||||
AddCategoryMapping(11, TorznabCatType.Audio);
|
||||
AddCategoryMapping(15, TorznabCatType.TV);
|
||||
//AddCategoryMapping(18, TorznabCatType.); Other
|
||||
AddCategoryMapping(16, TorznabCatType.TVDocumentary);
|
||||
AddCategoryMapping(25, TorznabCatType.Movies3D);
|
||||
AddCategoryMapping(20, TorznabCatType.MoviesBluRay);
|
||||
AddCategoryMapping(2, TorznabCatType.MoviesSD);
|
||||
AddCategoryMapping(3, TorznabCatType.MoviesForeign); //RO
|
||||
AddCategoryMapping(4, TorznabCatType.MoviesHD);
|
||||
AddCategoryMapping(19, TorznabCatType.MoviesForeign); // RO
|
||||
AddCategoryMapping(1, TorznabCatType.MoviesSD);
|
||||
AddCategoryMapping(10, TorznabCatType.Console);
|
||||
AddCategoryMapping(9, TorznabCatType.PCGames);
|
||||
//AddCategoryMapping(17, TorznabCatType); Linux No cat
|
||||
AddCategoryMapping(22, TorznabCatType.PCPhoneOther); //Apps/mobile
|
||||
AddCategoryMapping(8, TorznabCatType.PC);
|
||||
AddCategoryMapping(21, TorznabCatType.TVHD);
|
||||
AddCategoryMapping(23, TorznabCatType.TVSD);
|
||||
AddCategoryMapping(13, TorznabCatType.TVSport);
|
||||
AddCategoryMapping(14, TorznabCatType.TV);
|
||||
AddCategoryMapping(12, TorznabCatType.AudioVideo);
|
||||
AddCategoryMapping(7, TorznabCatType.XXX);
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
|
||||
{
|
||||
CQ dom = result.Content;
|
||||
var errorMessage = dom[".main"].Text().Trim();
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var searchUrl = BrowseUrl;
|
||||
var searchString = query.GetQueryString();
|
||||
|
||||
var cats = MapTorznabCapsToTrackers(query);
|
||||
string cat = "0";
|
||||
if (cats.Count == 1)
|
||||
{
|
||||
cat = cats[0];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchString) || cat != "0")
|
||||
searchUrl += string.Format("?search={0}&cat={1}&searchin=0&sort=0", HttpUtility.UrlEncode(searchString), cat);
|
||||
|
||||
|
||||
|
||||
var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl);
|
||||
var results = response.Content;
|
||||
try
|
||||
{
|
||||
CQ dom = results;
|
||||
var rows = dom[".torrentrow"];
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
var qRow = row.Cq();
|
||||
var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First();
|
||||
release.Title = qRow.Find(".torrenttable:eq(1) a b").Text().Trim();
|
||||
release.Description = release.Title;
|
||||
release.Guid = new Uri(SiteLink + qTitleLink.Attr("href"));
|
||||
release.Comments = release.Guid;
|
||||
|
||||
//22:05:3716/02/2013
|
||||
var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim();
|
||||
release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy", CultureInfo.InvariantCulture).AddHours(-2);
|
||||
|
||||
var qLink = qRow.Find(".torrenttable:eq(2) a").First();
|
||||
release.Link = new Uri(SiteLink + qLink.Attr("href"));
|
||||
|
||||
var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim();
|
||||
release.Size = ReleaseInfo.GetBytes(sizeStr);
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim());
|
||||
release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders;
|
||||
|
||||
var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15);
|
||||
release.Category = MapTrackerCatToNewznab(catId);
|
||||
|
||||
// Skip other
|
||||
if (release.Category != 0)
|
||||
{
|
||||
// Skip Romanian releases
|
||||
if (release.Category == TorznabCatType.MoviesForeign.ID && !configData.IncludeRomanianReleases.Value)
|
||||
continue;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using Jackett.Models.IndexerConfig.Bespoke;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class FileList : BaseIndexer, IIndexer
|
||||
{
|
||||
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
|
||||
string BrowseUrl { get { return SiteLink + "browse.php"; } }
|
||||
|
||||
new ConfigurationDataFileList configData
|
||||
{
|
||||
get { return (ConfigurationDataFileList)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "FileList",
|
||||
description: "The best Romanian site.",
|
||||
link: "http://filelist.ro/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataFileList())
|
||||
{
|
||||
AddCategoryMapping(24, TorznabCatType.TVAnime);
|
||||
AddCategoryMapping(11, TorznabCatType.Audio);
|
||||
AddCategoryMapping(15, TorznabCatType.TV);
|
||||
//AddCategoryMapping(18, TorznabCatType.); Other
|
||||
AddCategoryMapping(16, TorznabCatType.TVDocumentary);
|
||||
AddCategoryMapping(25, TorznabCatType.Movies3D);
|
||||
AddCategoryMapping(20, TorznabCatType.MoviesBluRay);
|
||||
AddCategoryMapping(2, TorznabCatType.MoviesSD);
|
||||
AddCategoryMapping(3, TorznabCatType.MoviesForeign); //RO
|
||||
AddCategoryMapping(4, TorznabCatType.MoviesHD);
|
||||
AddCategoryMapping(19, TorznabCatType.MoviesForeign); // RO
|
||||
AddCategoryMapping(1, TorznabCatType.MoviesSD);
|
||||
AddCategoryMapping(10, TorznabCatType.Console);
|
||||
AddCategoryMapping(9, TorznabCatType.PCGames);
|
||||
//AddCategoryMapping(17, TorznabCatType); Linux No cat
|
||||
AddCategoryMapping(22, TorznabCatType.PCPhoneOther); //Apps/mobile
|
||||
AddCategoryMapping(8, TorznabCatType.PC);
|
||||
AddCategoryMapping(21, TorznabCatType.TVHD);
|
||||
AddCategoryMapping(23, TorznabCatType.TVSD);
|
||||
AddCategoryMapping(13, TorznabCatType.TVSport);
|
||||
AddCategoryMapping(14, TorznabCatType.TV);
|
||||
AddCategoryMapping(12, TorznabCatType.AudioVideo);
|
||||
AddCategoryMapping(7, TorznabCatType.XXX);
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
|
||||
{
|
||||
CQ dom = result.Content;
|
||||
var errorMessage = dom[".main"].Text().Trim();
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var searchUrl = BrowseUrl;
|
||||
var searchString = query.GetQueryString();
|
||||
|
||||
var cats = MapTorznabCapsToTrackers(query);
|
||||
string cat = "0";
|
||||
if (cats.Count == 1)
|
||||
{
|
||||
cat = cats[0];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchString) || cat != "0")
|
||||
searchUrl += string.Format("?search={0}&cat={1}&searchin=0&sort=0", HttpUtility.UrlEncode(searchString), cat);
|
||||
|
||||
|
||||
|
||||
var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl);
|
||||
var results = response.Content;
|
||||
try
|
||||
{
|
||||
CQ dom = results;
|
||||
var rows = dom[".torrentrow"];
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
var qRow = row.Cq();
|
||||
var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First();
|
||||
release.Title = qRow.Find(".torrenttable:eq(1) a b").Text().Trim();
|
||||
release.Description = release.Title;
|
||||
release.Guid = new Uri(SiteLink + qTitleLink.Attr("href"));
|
||||
release.Comments = release.Guid;
|
||||
|
||||
//22:05:3716/02/2013
|
||||
var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim();
|
||||
release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy", CultureInfo.InvariantCulture).AddHours(-2);
|
||||
|
||||
var qLink = qRow.Find(".torrenttable:eq(2) a").First();
|
||||
release.Link = new Uri(SiteLink + qLink.Attr("href"));
|
||||
|
||||
var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim();
|
||||
release.Size = ReleaseInfo.GetBytes(sizeStr);
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim());
|
||||
release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders;
|
||||
|
||||
var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15);
|
||||
release.Category = MapTrackerCatToNewznab(catId);
|
||||
|
||||
// Skip other
|
||||
if (release.Category != 0)
|
||||
{
|
||||
// Skip Romanian releases
|
||||
if (release.Category == TorznabCatType.MoviesForeign.ID && !configData.IncludeRomanianReleases.Value)
|
||||
continue;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -193,7 +193,7 @@ namespace Jackett.Indexers
|
||||
}
|
||||
else if (imgUrl == "/pic/TV.png")
|
||||
{
|
||||
release.TheTvDbId = long.Parse(url.Substring(url.LastIndexOf('=') + 1));
|
||||
release.TVDBId = long.Parse(url.Substring(url.LastIndexOf('=') + 1));
|
||||
}
|
||||
}
|
||||
var nextPage = dom["#torrent-table-wrapper + p[align=center]"].Children().Last();
|
||||
|
@@ -1,232 +1,233 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jackett.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using Jackett.Utils;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using CsQuery;
|
||||
using System.Web;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils.Clients;
|
||||
using System.Text.RegularExpressions;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class RuTor : BaseIndexer, IIndexer
|
||||
{
|
||||
private string SearchUrl { get { return SiteLink + "search/0/{0}/000/0/{1}"; } }
|
||||
private string BrowseUrl { get { return SiteLink + "browse/0/{0}/0/0"; } }
|
||||
readonly static string defaultSiteLink = "http://rutor.org/";
|
||||
|
||||
new ConfigurationDataRuTor configData
|
||||
{
|
||||
get { return (ConfigurationDataRuTor)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public RuTor(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
|
||||
: base(name: "RUTor",
|
||||
description: "Свободный торрент трекер",
|
||||
link: "http://rutor.org/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataRuTor(defaultSiteLink))
|
||||
{
|
||||
TorznabCaps.Categories.Add(TorznabCatType.TVAnime);
|
||||
TorznabCaps.Categories.Add(TorznabCatType.Movies);
|
||||
TorznabCaps.Categories.Add(TorznabCatType.Audio);
|
||||
TorznabCaps.Categories.Add(TorznabCatType.Books);
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
var oldConfig = configData;
|
||||
var releases = await PerformQuery(new TorznabQuery());
|
||||
|
||||
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
|
||||
{
|
||||
configData = oldConfig;
|
||||
throw new Exception("Could not find releases from this URL");
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
|
||||
protected override void SaveConfig()
|
||||
{
|
||||
indexerService.SaveConfig(this as IIndexer, JsonConvert.SerializeObject(configData));
|
||||
}
|
||||
|
||||
// Override to load legacy config format
|
||||
public override void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
var json = jsonConfig.ToString();
|
||||
configData = JsonConvert.DeserializeObject<ConfigurationDataRuTor>(json);
|
||||
IsConfigured = true;
|
||||
}
|
||||
|
||||
private readonly int CAT_ANY = 0;
|
||||
private readonly int CAT_FOREIGN_MOVIE = 1;
|
||||
// private readonly int CAT_OUR_MOVIES = 5;
|
||||
// private readonly int CAT_POP_SCIFI_MOVIES = 12;
|
||||
private readonly int CAT_TV_SERIES = 4;
|
||||
// private readonly int CAT_TV = 6;
|
||||
// private readonly int CAT_ANIMATION = 7;
|
||||
private readonly int CAT_ANIME = 10;
|
||||
private readonly int CAT_MUSIC = 2;
|
||||
// private readonly int CAT_GAMES = 8;
|
||||
// private readonly int CAT_SOFTWARE = 9;
|
||||
// private readonly int CAT_SPORTS_HEALTH = 13;
|
||||
// private readonly int CAT_HUMOR = 15;
|
||||
// private readonly int CAT_ECONOMY_LIFE = 14;
|
||||
private readonly int CAT_BOOKS = 11;
|
||||
// private readonly int CAT_OTHER = 3;
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var searchString = query.GetQueryString();
|
||||
var searchCategory = CAT_ANY;
|
||||
|
||||
if (query.Categories.Contains(TorznabCatType.TV.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.TVHD.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.TVSD.ID))
|
||||
{
|
||||
searchCategory = CAT_TV_SERIES;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.Movies.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.MoviesForeign.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.MoviesHD.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.MoviesSD.ID)))
|
||||
{
|
||||
searchCategory = CAT_FOREIGN_MOVIE;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.TVAnime.ID)))
|
||||
{
|
||||
searchCategory = CAT_ANIME;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.Books.ID)))
|
||||
{
|
||||
searchCategory = CAT_BOOKS;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.Audio.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.AudioLossless.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.AudioMP3.ID)))
|
||||
{
|
||||
searchCategory = CAT_MUSIC;
|
||||
}
|
||||
|
||||
string queryUrl = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
queryUrl = string.Format(BrowseUrl, searchCategory);
|
||||
}
|
||||
else
|
||||
{
|
||||
queryUrl = string.Format(SearchUrl, searchCategory, HttpUtility.UrlEncode(searchString.Trim()));
|
||||
}
|
||||
|
||||
var results = await RequestStringWithCookiesAndRetry(queryUrl, string.Empty);
|
||||
try
|
||||
{
|
||||
CQ dom = results.Content;
|
||||
var rows = dom["#index table tr"];
|
||||
foreach (var row in rows.Skip(1))
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 172800;
|
||||
|
||||
var date = StringUtil.StripNonAlphaNumeric(row.Cq().Find("td:eq(0)").Text().Trim()
|
||||
.Replace("Янв", "01")
|
||||
.Replace("Фев", "02")
|
||||
.Replace("Мар", "03")
|
||||
.Replace("Апр", "04")
|
||||
.Replace("Май", "05")
|
||||
.Replace("Июн", "06")
|
||||
.Replace("Июл", "07")
|
||||
.Replace("Авг", "08")
|
||||
.Replace("Сен", "09")
|
||||
.Replace("Окт", "10")
|
||||
.Replace("Ноя", "11")
|
||||
.Replace("Дек", "12"));
|
||||
|
||||
release.PublishDate = DateTime.ParseExact(date, "ddMMyy", CultureInfo.InvariantCulture);
|
||||
|
||||
var hasTorrent = row.Cq().Find("td:eq(1) a").Length == 3;
|
||||
var titleIndex = 1;
|
||||
if (hasTorrent)
|
||||
titleIndex++;
|
||||
|
||||
release.Title = row.Cq().Find("td:eq(" + titleIndex + ")").Text().Trim();
|
||||
if (configData.StripRussian.Value)
|
||||
{
|
||||
var split = release.Title.IndexOf('/');
|
||||
if (split > -1)
|
||||
{
|
||||
release.Title = release.Title.Substring(split + 1).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
release.Description = release.Title;
|
||||
|
||||
var hasComments = row.Cq().Find("td:eq(2) img").Length > 0;
|
||||
var sizeCol = 2;
|
||||
|
||||
if (hasComments)
|
||||
sizeCol++;
|
||||
|
||||
var sizeStr = StringUtil.StripRegex(row.Cq().Find("td:eq(" + sizeCol + ")").Text(), "[^a-zA-Z0-9\\. -]", " ").Trim();
|
||||
string[] sizeSplit = sizeStr.Split(' ');
|
||||
release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0]));
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(row.Cq().Find(".green").Text().Trim());
|
||||
release.Peers = ParseUtil.CoerceInt(row.Cq().Find(".red").Text().Trim()) + release.Seeders;
|
||||
|
||||
release.Guid = new Uri(configData.Url.Value + row.Cq().Find("td:eq(1) a:eq(" + titleIndex + ")").Attr("href").Substring(1));
|
||||
release.Comments = release.Guid;
|
||||
|
||||
if (hasTorrent)
|
||||
{
|
||||
release.Link = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href"));
|
||||
release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(1)").Attr("href"));
|
||||
}
|
||||
else
|
||||
{
|
||||
release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href"));
|
||||
}
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jackett.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using Jackett.Utils;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using CsQuery;
|
||||
using System.Web;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils.Clients;
|
||||
using System.Text.RegularExpressions;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using Jackett.Models.IndexerConfig.Bespoke;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class RuTor : BaseIndexer, IIndexer
|
||||
{
|
||||
private string SearchUrl { get { return SiteLink + "search/0/{0}/000/0/{1}"; } }
|
||||
private string BrowseUrl { get { return SiteLink + "browse/0/{0}/0/0"; } }
|
||||
readonly static string defaultSiteLink = "http://rutor.org/";
|
||||
|
||||
new ConfigurationDataRuTor configData
|
||||
{
|
||||
get { return (ConfigurationDataRuTor)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public RuTor(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
|
||||
: base(name: "RUTor",
|
||||
description: "Свободный торрент трекер",
|
||||
link: "http://rutor.org/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataRuTor(defaultSiteLink))
|
||||
{
|
||||
TorznabCaps.Categories.Add(TorznabCatType.TVAnime);
|
||||
TorznabCaps.Categories.Add(TorznabCatType.Movies);
|
||||
TorznabCaps.Categories.Add(TorznabCatType.Audio);
|
||||
TorznabCaps.Categories.Add(TorznabCatType.Books);
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
var oldConfig = configData;
|
||||
var releases = await PerformQuery(new TorznabQuery());
|
||||
|
||||
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
|
||||
{
|
||||
configData = oldConfig;
|
||||
throw new Exception("Could not find releases from this URL");
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
|
||||
protected override void SaveConfig()
|
||||
{
|
||||
indexerService.SaveConfig(this as IIndexer, JsonConvert.SerializeObject(configData));
|
||||
}
|
||||
|
||||
// Override to load legacy config format
|
||||
public override void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
var json = jsonConfig.ToString();
|
||||
configData = JsonConvert.DeserializeObject<ConfigurationDataRuTor>(json);
|
||||
IsConfigured = true;
|
||||
}
|
||||
|
||||
private readonly int CAT_ANY = 0;
|
||||
private readonly int CAT_FOREIGN_MOVIE = 1;
|
||||
// private readonly int CAT_OUR_MOVIES = 5;
|
||||
// private readonly int CAT_POP_SCIFI_MOVIES = 12;
|
||||
private readonly int CAT_TV_SERIES = 4;
|
||||
// private readonly int CAT_TV = 6;
|
||||
// private readonly int CAT_ANIMATION = 7;
|
||||
private readonly int CAT_ANIME = 10;
|
||||
private readonly int CAT_MUSIC = 2;
|
||||
// private readonly int CAT_GAMES = 8;
|
||||
// private readonly int CAT_SOFTWARE = 9;
|
||||
// private readonly int CAT_SPORTS_HEALTH = 13;
|
||||
// private readonly int CAT_HUMOR = 15;
|
||||
// private readonly int CAT_ECONOMY_LIFE = 14;
|
||||
private readonly int CAT_BOOKS = 11;
|
||||
// private readonly int CAT_OTHER = 3;
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var searchString = query.GetQueryString();
|
||||
var searchCategory = CAT_ANY;
|
||||
|
||||
if (query.Categories.Contains(TorznabCatType.TV.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.TVHD.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.TVSD.ID))
|
||||
{
|
||||
searchCategory = CAT_TV_SERIES;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.Movies.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.MoviesForeign.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.MoviesHD.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.MoviesSD.ID)))
|
||||
{
|
||||
searchCategory = CAT_FOREIGN_MOVIE;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.TVAnime.ID)))
|
||||
{
|
||||
searchCategory = CAT_ANIME;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.Books.ID)))
|
||||
{
|
||||
searchCategory = CAT_BOOKS;
|
||||
}
|
||||
|
||||
if ((searchCategory == CAT_ANY) &&
|
||||
(query.Categories.Contains(TorznabCatType.Audio.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.AudioLossless.ID) ||
|
||||
query.Categories.Contains(TorznabCatType.AudioMP3.ID)))
|
||||
{
|
||||
searchCategory = CAT_MUSIC;
|
||||
}
|
||||
|
||||
string queryUrl = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
queryUrl = string.Format(BrowseUrl, searchCategory);
|
||||
}
|
||||
else
|
||||
{
|
||||
queryUrl = string.Format(SearchUrl, searchCategory, HttpUtility.UrlEncode(searchString.Trim()));
|
||||
}
|
||||
|
||||
var results = await RequestStringWithCookiesAndRetry(queryUrl, string.Empty);
|
||||
try
|
||||
{
|
||||
CQ dom = results.Content;
|
||||
var rows = dom["#index table tr"];
|
||||
foreach (var row in rows.Skip(1))
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 172800;
|
||||
|
||||
var date = StringUtil.StripNonAlphaNumeric(row.Cq().Find("td:eq(0)").Text().Trim()
|
||||
.Replace("Янв", "01")
|
||||
.Replace("Фев", "02")
|
||||
.Replace("Мар", "03")
|
||||
.Replace("Апр", "04")
|
||||
.Replace("Май", "05")
|
||||
.Replace("Июн", "06")
|
||||
.Replace("Июл", "07")
|
||||
.Replace("Авг", "08")
|
||||
.Replace("Сен", "09")
|
||||
.Replace("Окт", "10")
|
||||
.Replace("Ноя", "11")
|
||||
.Replace("Дек", "12"));
|
||||
|
||||
release.PublishDate = DateTime.ParseExact(date, "ddMMyy", CultureInfo.InvariantCulture);
|
||||
|
||||
var hasTorrent = row.Cq().Find("td:eq(1) a").Length == 3;
|
||||
var titleIndex = 1;
|
||||
if (hasTorrent)
|
||||
titleIndex++;
|
||||
|
||||
release.Title = row.Cq().Find("td:eq(" + titleIndex + ")").Text().Trim();
|
||||
if (configData.StripRussian.Value)
|
||||
{
|
||||
var split = release.Title.IndexOf('/');
|
||||
if (split > -1)
|
||||
{
|
||||
release.Title = release.Title.Substring(split + 1).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
release.Description = release.Title;
|
||||
|
||||
var hasComments = row.Cq().Find("td:eq(2) img").Length > 0;
|
||||
var sizeCol = 2;
|
||||
|
||||
if (hasComments)
|
||||
sizeCol++;
|
||||
|
||||
var sizeStr = StringUtil.StripRegex(row.Cq().Find("td:eq(" + sizeCol + ")").Text(), "[^a-zA-Z0-9\\. -]", " ").Trim();
|
||||
string[] sizeSplit = sizeStr.Split(' ');
|
||||
release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0]));
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(row.Cq().Find(".green").Text().Trim());
|
||||
release.Peers = ParseUtil.CoerceInt(row.Cq().Find(".red").Text().Trim()) + release.Seeders;
|
||||
|
||||
release.Guid = new Uri(configData.Url.Value + row.Cq().Find("td:eq(1) a:eq(" + titleIndex + ")").Attr("href").Substring(1));
|
||||
release.Comments = release.Guid;
|
||||
|
||||
if (hasTorrent)
|
||||
{
|
||||
release.Link = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href"));
|
||||
release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(1)").Attr("href"));
|
||||
}
|
||||
else
|
||||
{
|
||||
release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href"));
|
||||
}
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
216
src/Jackett/Indexers/Shazbat.cs
Normal file
216
src/Jackett/Indexers/Shazbat.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class Shazbat : BaseIndexer, IIndexer
|
||||
{
|
||||
private string LoginUrl { get { return SiteLink + "login"; } }
|
||||
private string SearchUrl { get { return SiteLink + "search"; } }
|
||||
private string TorrentsUrl { get { return SiteLink + "torrents"; } }
|
||||
private string RSSProfile { get { return SiteLink + "rss_feeds"; } }
|
||||
|
||||
new ConfigurationDataBasicLoginWithRSS configData
|
||||
{
|
||||
get { return (ConfigurationDataBasicLoginWithRSS)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public Shazbat(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
|
||||
: base(name: "Shazbat",
|
||||
description: "Modern indexer",
|
||||
link: "http://www.shazbat.tv/",
|
||||
caps: new TorznabCapabilities(TorznabCatType.TV,
|
||||
TorznabCatType.TVHD,
|
||||
TorznabCatType.TVSD),
|
||||
manager: i,
|
||||
client: c,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataBasicLoginWithRSS())
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "referer", "login"},
|
||||
{ "query", ""},
|
||||
{ "tv_login", configData.Username.Value },
|
||||
{ "tv_password", configData.Password.Value },
|
||||
{ "email", "" }
|
||||
};
|
||||
|
||||
// Get cookie
|
||||
var firstRequest = await RequestStringWithCookiesAndRetry(LoginUrl);
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("glyphicon-log-out"), () =>
|
||||
{
|
||||
throw new ExceptionWithConfigData("The username and password entered do not match.", configData);
|
||||
});
|
||||
|
||||
var rssProfile = await RequestStringWithCookiesAndRetry(RSSProfile);
|
||||
CQ rssDom = rssProfile.Content;
|
||||
configData.RSSKey.Value = rssDom.Find(".col-sm-9:eq(0)").Text().Trim();
|
||||
if (string.IsNullOrWhiteSpace(configData.RSSKey.Value))
|
||||
{
|
||||
throw new ExceptionWithConfigData("Failed to find RSS key.", configData);
|
||||
}
|
||||
|
||||
SaveConfig();
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
var queryString = query.GetQueryString();
|
||||
var url = TorrentsUrl;
|
||||
|
||||
WebClientStringResult results = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(queryString))
|
||||
{
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "search", queryString},
|
||||
{ "portlet", "true"}
|
||||
};
|
||||
|
||||
results = await PostDataWithCookiesAndRetry(SearchUrl, pairs, null, TorrentsUrl);
|
||||
|
||||
try
|
||||
{
|
||||
CQ dom = results.Content;
|
||||
var rows = dom["#torrent-table tr"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(queryString))
|
||||
{
|
||||
rows = dom["table tr"];
|
||||
}
|
||||
|
||||
foreach (var row in rows.Skip(1))
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
var qRow = row.Cq();
|
||||
var titleRow = qRow.Find("td:eq(2)").First();
|
||||
titleRow.Children().Remove();
|
||||
release.Title = titleRow.Text().Trim();
|
||||
if (string.IsNullOrWhiteSpace(release.Title))
|
||||
continue;
|
||||
release.Description = release.Title;
|
||||
|
||||
var qLink = row.Cq().Find("td:eq(4) a:eq(0)");
|
||||
release.Link = new Uri(SiteLink + qLink.Attr("href"));
|
||||
release.Guid = release.Link;
|
||||
var qLinkComm = row.Cq().Find("td:eq(4) a:eq(1)");
|
||||
release.Comments = new Uri(SiteLink + qLinkComm.Attr("href"));
|
||||
|
||||
var dateString = qRow.Find(".datetime").Attr("data-timestamp");
|
||||
release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString));
|
||||
var infoString = row.Cq().Find("td:eq(3)").Text();
|
||||
|
||||
release.Size = ParseUtil.CoerceLong(Regex.Match(infoString, "\\((\\d+)\\)").Value.Replace("(", "").Replace(")", ""));
|
||||
|
||||
var infosplit = infoString.Replace("/", string.Empty).Split(":".ToCharArray());
|
||||
release.Seeders = ParseUtil.CoerceInt(infosplit[1]);
|
||||
release.Peers = release.Seeders + ParseUtil.CoerceInt(infosplit[2]);
|
||||
|
||||
// var tags = row.Cq().Find(".label-tag").Text(); These don't see to parse - bad tags?
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var rssUrl = SiteLink + "rss/recent?passkey=" + configData.RSSKey.Value;
|
||||
|
||||
results = await RequestStringWithCookiesAndRetry(rssUrl);
|
||||
try
|
||||
{
|
||||
var doc = XDocument.Parse(results.Content);
|
||||
foreach (var result in doc.Descendants("item"))
|
||||
{
|
||||
var xTitle = result.Element("title").Value;
|
||||
var xLink = result.Element("link").Value;
|
||||
var xGUID = result.Element("guid").Value;
|
||||
var xDesc = result.Element("description").Value;
|
||||
var xDate = result.Element("pubDate").Value;
|
||||
var release = new ReleaseInfo();
|
||||
release.Guid =release.Link = new Uri(xLink);
|
||||
release.MinimumRatio = 1;
|
||||
release.Seeders = 1; // We are not supplied with peer info so just mark it as one.
|
||||
foreach (var element in xDesc.Split(";".ToCharArray()))
|
||||
{
|
||||
var split = element.IndexOf(':');
|
||||
if (split > -1)
|
||||
{
|
||||
var key = element.Substring(0, split).Trim();
|
||||
var value = element.Substring(split+1).Trim();
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case "Filename":
|
||||
release.Title = release.Description = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//"Thu, 24 Sep 2015 18:07:07 +0000"
|
||||
release.PublishDate = DateTime.ParseExact(xDate, "ddd, dd MMM yyyy HH:mm:ss +0000", CultureInfo.InvariantCulture);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(release.Title))
|
||||
{
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var release in releases)
|
||||
{
|
||||
if (release.Title.Contains("1080p") || release.Title.Contains("720p"))
|
||||
{
|
||||
release.Category = TorznabCatType.TVHD.ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
release.Category = TorznabCatType.TVSD.ID;
|
||||
}
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,172 +1,173 @@
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class Strike : BaseIndexer, IIndexer
|
||||
{
|
||||
readonly static string defaultSiteLink = "https://getstrike.net/";
|
||||
|
||||
private Uri BaseUri
|
||||
{
|
||||
get { return new Uri(configData.Url.Value); }
|
||||
set { configData.Url.Value = value.ToString(); }
|
||||
}
|
||||
|
||||
private string SearchUrl { get { return BaseUri + "api/v2/torrents/search/?phrase={0}"; } }
|
||||
private string DownloadUrl { get { return BaseUri + "torrents/api/download/{0}.torrent"; } }
|
||||
|
||||
new ConfigurationDataStrike configData
|
||||
{
|
||||
get { return (ConfigurationDataStrike)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
|
||||
public Strike(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
|
||||
: base(name: "Strike",
|
||||
description: "Torrent search engine",
|
||||
link: defaultSiteLink,
|
||||
caps: new TorznabCapabilities(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataStrike(defaultSiteLink))
|
||||
{
|
||||
AddCategoryMapping("Anime", TorznabCatType.TVAnime);
|
||||
AddCategoryMapping("Applications", TorznabCatType.PC);
|
||||
AddCategoryMapping("Books", TorznabCatType.Books);
|
||||
AddCategoryMapping("Games", TorznabCatType.PCGames);
|
||||
AddCategoryMapping("Movies", TorznabCatType.Movies);
|
||||
AddCategoryMapping("TV", TorznabCatType.TV);
|
||||
AddCategoryMapping("XXX", TorznabCatType.XXX);
|
||||
AddCategoryMapping("Music", TorznabCatType.Audio);
|
||||
|
||||
/*AddCategoryMapping("Movies:Highres Movies", TorznabCatType.MoviesHD);
|
||||
AddCategoryMapping("Movies:3D Movies", TorznabCatType.Movies3D);
|
||||
AddCategoryMapping("Books:Ebooks", TorznabCatType.BooksEbook);
|
||||
AddCategoryMapping("Books:Comics", TorznabCatType.BooksComics);
|
||||
AddCategoryMapping("Books:Audio Books", TorznabCatType.AudioAudiobook);
|
||||
AddCategoryMapping("Games:XBOX360", TorznabCatType.ConsoleXbox360);
|
||||
AddCategoryMapping("Games:Wii", TorznabCatType.ConsoleWii);
|
||||
AddCategoryMapping("Games:PSP", TorznabCatType.ConsolePSP);
|
||||
AddCategoryMapping("Games:PS3", TorznabCatType.ConsolePS3);
|
||||
AddCategoryMapping("Games:PC", TorznabCatType.PCGames);
|
||||
AddCategoryMapping("Games:Android", TorznabCatType.PCPhoneAndroid);
|
||||
AddCategoryMapping("Music:Mp3", TorznabCatType.AudioMP3);*/
|
||||
}
|
||||
|
||||
public 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;
|
||||
}
|
||||
|
||||
// Override to load legacy config format
|
||||
public override void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
if (jsonConfig is JObject)
|
||||
{
|
||||
BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
|
||||
SaveConfig();
|
||||
IsConfigured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
base.LoadFromSavedConfiguration(jsonConfig);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
List<ReleaseInfo> releases = new List<ReleaseInfo>();
|
||||
var queryString = query.GetQueryString();
|
||||
var searchTerm = string.IsNullOrEmpty(queryString) ? DateTime.Now.Year.ToString() : queryString;
|
||||
var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchTerm));
|
||||
|
||||
var trackerCategories = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true);
|
||||
|
||||
// This tracker can only search one cat at a time, otherwise search all and filter results
|
||||
if (trackerCategories.Count == 1)
|
||||
{
|
||||
episodeSearchUrl += "&category=" + trackerCategories[0];
|
||||
}
|
||||
|
||||
var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty);
|
||||
try
|
||||
{
|
||||
var jResults = JObject.Parse(results.Content);
|
||||
foreach (JObject result in (JArray)jResults["torrents"])
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 172800;
|
||||
|
||||
if (trackerCategories.Count > 0 && !trackerCategories.Contains((string)result["torrent_category"]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
release.Category = MapTrackerCatToNewznab((string)result["torrent_category"]);
|
||||
|
||||
release.Title = (string)result["torrent_title"];
|
||||
release.Description = release.Title;
|
||||
release.Seeders = (int)result["seeds"];
|
||||
release.Peers = (int)result["leeches"] + release.Seeders;
|
||||
release.Size = (long)result["size"];
|
||||
|
||||
// "Apr 2, 2015", "Apr 12, 2015" (note the spacing)
|
||||
// some are unix timestamps, some are not.. :/
|
||||
var dateString = string.Join(" ", ((string)result["upload_date"]).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
float dateVal;
|
||||
if (ParseUtil.TryCoerceFloat(dateString, out dateVal))
|
||||
release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(dateVal);
|
||||
else
|
||||
release.PublishDate = DateTime.ParseExact(dateString, "MMM d, yyyy", CultureInfo.InvariantCulture);
|
||||
|
||||
release.Guid = new Uri((string)result["page"]);
|
||||
release.Comments = release.Guid;
|
||||
|
||||
release.InfoHash = (string)result["torrent_hash"];
|
||||
release.MagnetUri = new Uri((string)result["magnet_uri"]);
|
||||
release.Link = new Uri(string.Format(DownloadUrl, release.InfoHash));
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
|
||||
public override Task<byte[]> Download(Uri link)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Collections.Specialized;
|
||||
using Jackett.Models.IndexerConfig.Bespoke;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class Strike : BaseIndexer, IIndexer
|
||||
{
|
||||
readonly static string defaultSiteLink = "https://getstrike.net/";
|
||||
|
||||
private Uri BaseUri
|
||||
{
|
||||
get { return new Uri(configData.Url.Value); }
|
||||
set { configData.Url.Value = value.ToString(); }
|
||||
}
|
||||
|
||||
private string SearchUrl { get { return BaseUri + "api/v2/torrents/search/?phrase={0}"; } }
|
||||
private string DownloadUrl { get { return BaseUri + "torrents/api/download/{0}.torrent"; } }
|
||||
|
||||
new ConfigurationDataStrike configData
|
||||
{
|
||||
get { return (ConfigurationDataStrike)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
|
||||
public Strike(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
|
||||
: base(name: "Strike",
|
||||
description: "Torrent search engine",
|
||||
link: defaultSiteLink,
|
||||
caps: new TorznabCapabilities(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataStrike(defaultSiteLink))
|
||||
{
|
||||
AddCategoryMapping("Anime", TorznabCatType.TVAnime);
|
||||
AddCategoryMapping("Applications", TorznabCatType.PC);
|
||||
AddCategoryMapping("Books", TorznabCatType.Books);
|
||||
AddCategoryMapping("Games", TorznabCatType.PCGames);
|
||||
AddCategoryMapping("Movies", TorznabCatType.Movies);
|
||||
AddCategoryMapping("TV", TorznabCatType.TV);
|
||||
AddCategoryMapping("XXX", TorznabCatType.XXX);
|
||||
AddCategoryMapping("Music", TorznabCatType.Audio);
|
||||
|
||||
/*AddCategoryMapping("Movies:Highres Movies", TorznabCatType.MoviesHD);
|
||||
AddCategoryMapping("Movies:3D Movies", TorznabCatType.Movies3D);
|
||||
AddCategoryMapping("Books:Ebooks", TorznabCatType.BooksEbook);
|
||||
AddCategoryMapping("Books:Comics", TorznabCatType.BooksComics);
|
||||
AddCategoryMapping("Books:Audio Books", TorznabCatType.AudioAudiobook);
|
||||
AddCategoryMapping("Games:XBOX360", TorznabCatType.ConsoleXbox360);
|
||||
AddCategoryMapping("Games:Wii", TorznabCatType.ConsoleWii);
|
||||
AddCategoryMapping("Games:PSP", TorznabCatType.ConsolePSP);
|
||||
AddCategoryMapping("Games:PS3", TorznabCatType.ConsolePS3);
|
||||
AddCategoryMapping("Games:PC", TorznabCatType.PCGames);
|
||||
AddCategoryMapping("Games:Android", TorznabCatType.PCPhoneAndroid);
|
||||
AddCategoryMapping("Music:Mp3", TorznabCatType.AudioMP3);*/
|
||||
}
|
||||
|
||||
public 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;
|
||||
}
|
||||
|
||||
// Override to load legacy config format
|
||||
public override void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
if (jsonConfig is JObject)
|
||||
{
|
||||
BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
|
||||
SaveConfig();
|
||||
IsConfigured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
base.LoadFromSavedConfiguration(jsonConfig);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
List<ReleaseInfo> releases = new List<ReleaseInfo>();
|
||||
var queryString = query.GetQueryString();
|
||||
var searchTerm = string.IsNullOrEmpty(queryString) ? DateTime.Now.Year.ToString() : queryString;
|
||||
var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchTerm));
|
||||
|
||||
var trackerCategories = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true);
|
||||
|
||||
// This tracker can only search one cat at a time, otherwise search all and filter results
|
||||
if (trackerCategories.Count == 1)
|
||||
{
|
||||
episodeSearchUrl += "&category=" + trackerCategories[0];
|
||||
}
|
||||
|
||||
var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty);
|
||||
try
|
||||
{
|
||||
var jResults = JObject.Parse(results.Content);
|
||||
foreach (JObject result in (JArray)jResults["torrents"])
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 172800;
|
||||
|
||||
if (trackerCategories.Count > 0 && !trackerCategories.Contains((string)result["torrent_category"]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
release.Category = MapTrackerCatToNewznab((string)result["torrent_category"]);
|
||||
|
||||
release.Title = (string)result["torrent_title"];
|
||||
release.Description = release.Title;
|
||||
release.Seeders = (int)result["seeds"];
|
||||
release.Peers = (int)result["leeches"] + release.Seeders;
|
||||
release.Size = (long)result["size"];
|
||||
|
||||
// "Apr 2, 2015", "Apr 12, 2015" (note the spacing)
|
||||
// some are unix timestamps, some are not.. :/
|
||||
var dateString = string.Join(" ", ((string)result["upload_date"]).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
float dateVal;
|
||||
if (ParseUtil.TryCoerceFloat(dateString, out dateVal))
|
||||
release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(dateVal);
|
||||
else
|
||||
release.PublishDate = DateTime.ParseExact(dateString, "MMM d, yyyy", CultureInfo.InvariantCulture);
|
||||
|
||||
release.Guid = new Uri((string)result["page"]);
|
||||
release.Comments = release.Guid;
|
||||
|
||||
release.InfoHash = (string)result["torrent_hash"];
|
||||
release.MagnetUri = new Uri((string)result["magnet_uri"]);
|
||||
release.Link = new Uri(string.Format(DownloadUrl, release.InfoHash));
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
|
||||
public override Task<byte[]> Download(Uri link)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ namespace Jackett.Indexers
|
||||
public class T411 : BaseIndexer, IIndexer
|
||||
{
|
||||
private readonly string CommentsUrl = "";
|
||||
const string ApiUrl = "http://api.t411.io";
|
||||
const string ApiUrl = "http://api.t411.in";
|
||||
const string AuthUrl = ApiUrl + "/auth";
|
||||
const string SearchUrl = ApiUrl + "/torrents/search/{0}";
|
||||
const string DownloadUrl = ApiUrl + "/torrents/download/{0}";
|
||||
@@ -38,7 +38,7 @@ namespace Jackett.Indexers
|
||||
public T411(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
|
||||
: base(name: "T411",
|
||||
description: "French Torrent Tracker",
|
||||
link: "http://www.t411.io/",
|
||||
link: "http://www.t411.in/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
|
@@ -1,168 +1,169 @@
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class NCore : BaseIndexer, IIndexer
|
||||
{
|
||||
private string LoginUrl { get { return SiteLink + "login.php"; } }
|
||||
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
|
||||
|
||||
new ConfigurationDataNCore configData
|
||||
{
|
||||
get { return (ConfigurationDataNCore)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "nCore",
|
||||
description: "A Hungarian private torrent site.",
|
||||
link: "https://ncore.cc/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataNCore())
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
|
||||
if (configData.Hungarian.Value == false && configData.English.Value == false)
|
||||
throw new ExceptionWithConfigData("Please select atleast one language.", configData);
|
||||
|
||||
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "nev", configData.Username.Value },
|
||||
{ "pass", configData.Password.Value },
|
||||
{ "ne_leptessen_ki", "1"},
|
||||
{ "set_lang", "en" },
|
||||
{ "submitted", "1" },
|
||||
{ "submit", "Access!" }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () =>
|
||||
{
|
||||
CQ dom = result.Content;
|
||||
var messageEl = dom["#hibauzenet table tbody tr"];
|
||||
var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1);
|
||||
var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login.";
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
List<KeyValuePair<string, string>> CreateKeyValueList(params string[][] keyValues)
|
||||
{
|
||||
var list = new List<KeyValuePair<string, string>>();
|
||||
foreach (var d in keyValues)
|
||||
{
|
||||
list.Add(new KeyValuePair<string, string>(d[0], d[1]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> GetSearchFormData(string searchString)
|
||||
{
|
||||
const string searchTypeKey = "kivalasztott_tipus[]";
|
||||
var baseList = CreateKeyValueList(
|
||||
new[] { "nyit_sorozat_resz", "true" },
|
||||
new[] { "miben", "name" },
|
||||
new[] { "tipus", "kivalasztottak_kozott" },
|
||||
new[] { "submit.x", "1" },
|
||||
new[] { "submit.y", "1" },
|
||||
new[] { "submit", "Ok" },
|
||||
new[] { "mire", searchString }
|
||||
);
|
||||
|
||||
if (configData.English.Value)
|
||||
{
|
||||
baseList.AddRange(CreateKeyValueList(
|
||||
new[] { searchTypeKey, "xvidser" },
|
||||
new[] { searchTypeKey, "dvdser" },
|
||||
new[] { searchTypeKey, "hdser" }
|
||||
));
|
||||
}
|
||||
|
||||
if (configData.Hungarian.Value)
|
||||
{
|
||||
baseList.AddRange(CreateKeyValueList(
|
||||
new[] { searchTypeKey, "xvidser_hun" },
|
||||
new[] { searchTypeKey, "dvdser_hun" },
|
||||
new[] { searchTypeKey, "hdser_hun" }
|
||||
));
|
||||
}
|
||||
return baseList;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(query.GetQueryString()));
|
||||
|
||||
try
|
||||
{
|
||||
CQ dom = results.Content;
|
||||
|
||||
ReleaseInfo release;
|
||||
var rows = dom[".box_torrent_all"].Find(".box_torrent");
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
CQ qRow = row.Cq();
|
||||
|
||||
release = new ReleaseInfo();
|
||||
var torrentTxt = qRow.Find(".torrent_txt").Find("a").Get(0);
|
||||
if (torrentTxt == null) continue;
|
||||
release.Title = torrentTxt.GetAttribute("title");
|
||||
release.Description = release.Title;
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 172800;
|
||||
|
||||
string downloadLink = SiteLink + torrentTxt.GetAttribute("href");
|
||||
string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4);
|
||||
|
||||
release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId);
|
||||
release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId);
|
||||
release.Guid = new Uri(release.Comments.ToString() + "#comments"); ;
|
||||
release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text());
|
||||
release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders;
|
||||
release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("<br />", " "), CultureInfo.InvariantCulture);
|
||||
string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' ');
|
||||
release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0]));
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
|
||||
|
||||
return releases.ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
using CsQuery;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using Jackett.Models.IndexerConfig.Bespoke;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class NCore : BaseIndexer, IIndexer
|
||||
{
|
||||
private string LoginUrl { get { return SiteLink + "login.php"; } }
|
||||
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
|
||||
|
||||
new ConfigurationDataNCore configData
|
||||
{
|
||||
get { return (ConfigurationDataNCore)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "nCore",
|
||||
description: "A Hungarian private torrent site.",
|
||||
link: "https://ncore.cc/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
manager: i,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataNCore())
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
configData.LoadValuesFromJson(configJson);
|
||||
|
||||
if (configData.Hungarian.Value == false && configData.English.Value == false)
|
||||
throw new ExceptionWithConfigData("Please select atleast one language.", configData);
|
||||
|
||||
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "nev", configData.Username.Value },
|
||||
{ "pass", configData.Password.Value },
|
||||
{ "ne_leptessen_ki", "1"},
|
||||
{ "set_lang", "en" },
|
||||
{ "submitted", "1" },
|
||||
{ "submit", "Access!" }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () =>
|
||||
{
|
||||
CQ dom = result.Content;
|
||||
var messageEl = dom["#hibauzenet table tbody tr"];
|
||||
var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1);
|
||||
var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login.";
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
List<KeyValuePair<string, string>> CreateKeyValueList(params string[][] keyValues)
|
||||
{
|
||||
var list = new List<KeyValuePair<string, string>>();
|
||||
foreach (var d in keyValues)
|
||||
{
|
||||
list.Add(new KeyValuePair<string, string>(d[0], d[1]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> GetSearchFormData(string searchString)
|
||||
{
|
||||
const string searchTypeKey = "kivalasztott_tipus[]";
|
||||
var baseList = CreateKeyValueList(
|
||||
new[] { "nyit_sorozat_resz", "true" },
|
||||
new[] { "miben", "name" },
|
||||
new[] { "tipus", "kivalasztottak_kozott" },
|
||||
new[] { "submit.x", "1" },
|
||||
new[] { "submit.y", "1" },
|
||||
new[] { "submit", "Ok" },
|
||||
new[] { "mire", searchString }
|
||||
);
|
||||
|
||||
if (configData.English.Value)
|
||||
{
|
||||
baseList.AddRange(CreateKeyValueList(
|
||||
new[] { searchTypeKey, "xvidser" },
|
||||
new[] { searchTypeKey, "dvdser" },
|
||||
new[] { searchTypeKey, "hdser" }
|
||||
));
|
||||
}
|
||||
|
||||
if (configData.Hungarian.Value)
|
||||
{
|
||||
baseList.AddRange(CreateKeyValueList(
|
||||
new[] { searchTypeKey, "xvidser_hun" },
|
||||
new[] { searchTypeKey, "dvdser_hun" },
|
||||
new[] { searchTypeKey, "hdser_hun" }
|
||||
));
|
||||
}
|
||||
return baseList;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(query.GetQueryString()));
|
||||
|
||||
try
|
||||
{
|
||||
CQ dom = results.Content;
|
||||
|
||||
ReleaseInfo release;
|
||||
var rows = dom[".box_torrent_all"].Find(".box_torrent");
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
CQ qRow = row.Cq();
|
||||
|
||||
release = new ReleaseInfo();
|
||||
var torrentTxt = qRow.Find(".torrent_txt").Find("a").Get(0);
|
||||
if (torrentTxt == null) continue;
|
||||
release.Title = torrentTxt.GetAttribute("title");
|
||||
release.Description = release.Title;
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 172800;
|
||||
|
||||
string downloadLink = SiteLink + torrentTxt.GetAttribute("href");
|
||||
string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4);
|
||||
|
||||
release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId);
|
||||
release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId);
|
||||
release.Guid = new Uri(release.Comments.ToString() + "#comments"); ;
|
||||
release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text());
|
||||
release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders;
|
||||
release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("<br />", " "), CultureInfo.InvariantCulture);
|
||||
string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' ');
|
||||
release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0]));
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results.Content, ex);
|
||||
}
|
||||
|
||||
|
||||
return releases.ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -185,6 +185,8 @@
|
||||
<Compile Include="Indexers\BitMeTV.cs" />
|
||||
<Compile Include="Indexers\Demonoid.cs" />
|
||||
<Compile Include="Indexers\FrenchTorrentDb.cs" />
|
||||
<Compile Include="Indexers\BroadcastTheNet.cs" />
|
||||
<Compile Include="Indexers\Shazbat.cs" />
|
||||
<Compile Include="Indexers\NxtGn.cs" />
|
||||
<Compile Include="Indexers\Freshon.cs" />
|
||||
<Compile Include="Indexers\HDSpace.cs" />
|
||||
@@ -194,6 +196,7 @@
|
||||
<Compile Include="Indexers\FileList.cs" />
|
||||
<Compile Include="Indexers\Abstract\AvistazTracker.cs" />
|
||||
<Compile Include="Indexers\AnimeTorrents.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataAPIKey.cs" />
|
||||
<Compile Include="Models\ManualSearchResult.cs" />
|
||||
<Compile Include="Indexers\Rarbg.cs" />
|
||||
<Compile Include="Indexers\TVChaosUK.cs" />
|
||||
@@ -221,14 +224,14 @@
|
||||
<Compile Include="Models\CategoryMapping.cs" />
|
||||
<Compile Include="Models\AdminSearch.cs" />
|
||||
<Compile Include="Models\IndexerConfigurationStatus.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataFileList.cs" />
|
||||
<Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataFileList.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataBasicLoginWithRSS.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataRecaptchaLogin.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataLoginTokin.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataNCore.cs" />
|
||||
<Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataNCore.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataCaptchaLogin.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataAnimeBytes.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataStrike.cs" />
|
||||
<Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataAnimeBytes.cs" />
|
||||
<Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataStrike.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataUrl.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ISerializableConfig.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataPinNumber.cs" />
|
||||
@@ -264,7 +267,7 @@
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationData.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataBasicLogin.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataCookie.cs" />
|
||||
<Compile Include="Models\IndexerConfig\ConfigurationDataRuTor.cs" />
|
||||
<Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataRuTor.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="CookieContainerExtensions.cs" />
|
||||
<Compile Include="Utils\Clients\WebRequest.cs" />
|
||||
@@ -368,7 +371,9 @@
|
||||
<Content Include="Content\custom.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\libs\filesize.min.js" />
|
||||
<Content Include="Content\libs\filesize.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\fonts\fontawesome-webfont.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -426,6 +431,9 @@
|
||||
<Content Include="Content\logos\beyondhd.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\logos\broadcastthenet.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\logos\demonoid.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -471,6 +479,9 @@
|
||||
<Content Include="Content\logos\scenetime.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\logos\shazbat.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\logos\showrss.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@@ -1,22 +1,22 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig
|
||||
{
|
||||
class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin
|
||||
{
|
||||
public BoolItem IncludeRaw { get; private set; }
|
||||
public DisplayItem DateWarning { get; private set; }
|
||||
|
||||
public ConfigurationDataAnimeBytes()
|
||||
: base()
|
||||
{
|
||||
IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false };
|
||||
DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" };
|
||||
}
|
||||
}
|
||||
}
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin
|
||||
{
|
||||
public BoolItem IncludeRaw { get; private set; }
|
||||
public DisplayItem DateWarning { get; private set; }
|
||||
|
||||
public ConfigurationDataAnimeBytes()
|
||||
: base()
|
||||
{
|
||||
IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false };
|
||||
DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" };
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,22 +1,22 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig
|
||||
{
|
||||
class ConfigurationDataFileList : ConfigurationDataBasicLogin
|
||||
{
|
||||
public BoolItem IncludeRomanianReleases { get; private set; }
|
||||
public DisplayItem CatWarning { get; private set; }
|
||||
|
||||
public ConfigurationDataFileList()
|
||||
: base()
|
||||
{
|
||||
IncludeRomanianReleases = new BoolItem() { Name = "IncludeRomanianReleases", Value = false };
|
||||
CatWarning = new DisplayItem("When mapping TV ensure you add category 5000 in addition to 5030,5040.") { Name = "CatWarning" };
|
||||
}
|
||||
}
|
||||
}
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
class ConfigurationDataFileList : ConfigurationDataBasicLogin
|
||||
{
|
||||
public BoolItem IncludeRomanianReleases { get; private set; }
|
||||
public DisplayItem CatWarning { get; private set; }
|
||||
|
||||
public ConfigurationDataFileList()
|
||||
: base()
|
||||
{
|
||||
IncludeRomanianReleases = new BoolItem() { Name = "IncludeRomanianReleases", Value = false };
|
||||
CatWarning = new DisplayItem("When mapping TV ensure you add category 5000 in addition to 5030,5040.") { Name = "CatWarning" };
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,62 +1,62 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig
|
||||
{
|
||||
public class ConfigurationDataNCore : ConfigurationData
|
||||
{
|
||||
public StringItem Username { get; private set; }
|
||||
public StringItem Password { get; private set; }
|
||||
public BoolItem Hungarian { get; set; }
|
||||
public BoolItem English { get; set; }
|
||||
|
||||
public ConfigurationDataNCore()
|
||||
{
|
||||
Username = new StringItem { Name = "Username", Value = "" };
|
||||
Password = new StringItem { Name = "Password", Value = "" };
|
||||
Hungarian = new BoolItem { Name = "Hungarian", Value = true };
|
||||
English = new BoolItem { Name = "English", Value = true };
|
||||
}
|
||||
|
||||
public ConfigurationDataNCore(JToken json)
|
||||
{
|
||||
ConfigurationDataNCore configData = new ConfigurationDataNCore();
|
||||
|
||||
dynamic configArray = JsonConvert.DeserializeObject(json.ToString());
|
||||
foreach (var config in configArray)
|
||||
{
|
||||
string propertyName = UppercaseFirst((string)config.id);
|
||||
switch (propertyName)
|
||||
{
|
||||
case "Username":
|
||||
Username = new StringItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
case "Password":
|
||||
Password = new StringItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
case "Hungarian":
|
||||
Hungarian = new BoolItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
case "English":
|
||||
English = new BoolItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string UppercaseFirst(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return string.Empty;
|
||||
return char.ToUpper(s[0]) + s.Substring(1);
|
||||
}
|
||||
}
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
public class ConfigurationDataNCore : ConfigurationData
|
||||
{
|
||||
public StringItem Username { get; private set; }
|
||||
public StringItem Password { get; private set; }
|
||||
public BoolItem Hungarian { get; set; }
|
||||
public BoolItem English { get; set; }
|
||||
|
||||
public ConfigurationDataNCore()
|
||||
{
|
||||
Username = new StringItem { Name = "Username", Value = "" };
|
||||
Password = new StringItem { Name = "Password", Value = "" };
|
||||
Hungarian = new BoolItem { Name = "Hungarian", Value = true };
|
||||
English = new BoolItem { Name = "English", Value = true };
|
||||
}
|
||||
|
||||
public ConfigurationDataNCore(JToken json)
|
||||
{
|
||||
ConfigurationDataNCore configData = new ConfigurationDataNCore();
|
||||
|
||||
dynamic configArray = JsonConvert.DeserializeObject(json.ToString());
|
||||
foreach (var config in configArray)
|
||||
{
|
||||
string propertyName = UppercaseFirst((string)config.id);
|
||||
switch (propertyName)
|
||||
{
|
||||
case "Username":
|
||||
Username = new StringItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
case "Password":
|
||||
Password = new StringItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
case "Hungarian":
|
||||
Hungarian = new BoolItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
case "English":
|
||||
English = new BoolItem { Name = propertyName, Value = config.value };
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string UppercaseFirst(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return string.Empty;
|
||||
return char.ToUpper(s[0]) + s.Substring(1);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,27 +1,27 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig
|
||||
{
|
||||
public class ConfigurationDataRuTor : ConfigurationData
|
||||
{
|
||||
[JsonProperty]
|
||||
public StringItem Url { get; private set; }
|
||||
[JsonProperty]
|
||||
public BoolItem StripRussian { get; private set; }
|
||||
|
||||
public ConfigurationDataRuTor()
|
||||
{
|
||||
}
|
||||
|
||||
public ConfigurationDataRuTor(string defaultUrl)
|
||||
{
|
||||
Url = new StringItem { Name = "Url", Value = defaultUrl };
|
||||
StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true };
|
||||
}
|
||||
}
|
||||
}
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
public class ConfigurationDataRuTor : ConfigurationData
|
||||
{
|
||||
[JsonProperty]
|
||||
public StringItem Url { get; private set; }
|
||||
[JsonProperty]
|
||||
public BoolItem StripRussian { get; private set; }
|
||||
|
||||
public ConfigurationDataRuTor()
|
||||
{
|
||||
}
|
||||
|
||||
public ConfigurationDataRuTor(string defaultUrl)
|
||||
{
|
||||
Url = new StringItem { Name = "Url", Value = defaultUrl };
|
||||
StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true };
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig
|
||||
{
|
||||
public class ConfigurationDataStrike : ConfigurationDataUrl
|
||||
{
|
||||
public DisplayItem StrikeWarning { get; private set; }
|
||||
|
||||
public ConfigurationDataStrike(string url) : base(url)
|
||||
{
|
||||
StrikeWarning = new DisplayItem("This indexer does not support RSS Sync, only Search") { Name = "Warning" };
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
public class ConfigurationDataStrike : ConfigurationDataUrl
|
||||
{
|
||||
public DisplayItem StrikeWarning { get; private set; }
|
||||
|
||||
public ConfigurationDataStrike(string url) : base(url)
|
||||
{
|
||||
StrikeWarning = new DisplayItem("This indexer does not support RSS Sync, only Search") { Name = "Warning" };
|
||||
}
|
||||
}
|
||||
}
|
18
src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs
Normal file
18
src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.IndexerConfig
|
||||
{
|
||||
public class ConfigurationDataAPIKey : ConfigurationData
|
||||
{
|
||||
public ConfigurationData.StringItem Key { get; private set; }
|
||||
|
||||
public ConfigurationDataAPIKey()
|
||||
{
|
||||
Key = new ConfigurationData.StringItem { Name = "APIKey", Value = string.Empty };
|
||||
}
|
||||
}
|
||||
}
|
@@ -21,11 +21,10 @@ namespace Jackett.Models
|
||||
public long? Size { get; set; }
|
||||
public string Description { get; set; }
|
||||
public long? RageID { get; set; }
|
||||
public long? TheTvDbId { get; set; }
|
||||
public long? TVDBId { get; set; }
|
||||
public long? Imdb { get; set; }
|
||||
public int? Seeders { get; set; }
|
||||
public int? Peers { get; set; }
|
||||
public Uri ConverUrl { get; set; }
|
||||
public Uri BannerUrl { get; set; }
|
||||
public string InfoHash { get; set; }
|
||||
public Uri MagnetUri { get; set; }
|
||||
@@ -48,7 +47,6 @@ namespace Jackett.Models
|
||||
Imdb = Imdb,
|
||||
Seeders = Seeders,
|
||||
Peers = Peers,
|
||||
ConverUrl = ConverUrl,
|
||||
BannerUrl = BannerUrl,
|
||||
InfoHash = InfoHash,
|
||||
MagnetUri = MagnetUri,
|
||||
|
@@ -81,7 +81,7 @@ namespace Jackett.Models
|
||||
),
|
||||
getTorznabElement("magneturl", r.MagnetUri),
|
||||
getTorznabElement("rageid", r.RageID),
|
||||
getTorznabElement("thetvdb", r.TheTvDbId),
|
||||
getTorznabElement("thetvdb", r.TVDBId),
|
||||
getTorznabElement("imdb", r.Imdb),
|
||||
getTorznabElement("seeders", r.Seeders),
|
||||
getTorznabElement("peers", r.Peers),
|
||||
|
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.6.5.0")]
|
||||
[assembly: AssemblyFileVersion("0.6.5.0")]
|
||||
[assembly: AssemblyVersion("0.6.7.0")]
|
||||
[assembly: AssemblyFileVersion("0.6.7.0")]
|
||||
|
@@ -13,11 +13,11 @@ namespace Jackett.Utils
|
||||
get {
|
||||
if (System.Environment.OSVersion.Platform == PlatformID.Unix)
|
||||
{
|
||||
return "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chrome/44.0.2403.155 Safari/537.36";
|
||||
return "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chrome/45.0.2454.101 Safari/537.36";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36";
|
||||
return "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using AutoMapper;
|
||||
using Jackett.Models;
|
||||
using Jackett.Services;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -13,11 +14,13 @@ namespace Jackett.Utils.Clients
|
||||
{
|
||||
public class HttpWebClient : IWebClient
|
||||
{
|
||||
private Logger logger;
|
||||
Logger logger;
|
||||
IConfigurationService configService;
|
||||
|
||||
public HttpWebClient(Logger l)
|
||||
public HttpWebClient(Logger l, IConfigurationService c)
|
||||
{
|
||||
logger = l;
|
||||
configService = c;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,13 +44,13 @@ namespace Jackett.Utils.Clients
|
||||
return Mapper.Map<WebClientStringResult>(result);
|
||||
}
|
||||
|
||||
private async Task<WebClientByteResult> Run(WebRequest request)
|
||||
private async Task<WebClientByteResult> Run(WebRequest webRequest)
|
||||
{
|
||||
var cookies = new CookieContainer();
|
||||
if (!string.IsNullOrEmpty(request.Cookies))
|
||||
if (!string.IsNullOrEmpty(webRequest.Cookies))
|
||||
{
|
||||
var uri = new Uri(request.Url);
|
||||
foreach (var c in request.Cookies.Split(';'))
|
||||
var uri = new Uri(webRequest.Url);
|
||||
foreach (var c in webRequest.Cookies.Split(';'))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -67,27 +70,52 @@ namespace Jackett.Utils.Clients
|
||||
UseCookies = true,
|
||||
});
|
||||
|
||||
client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent);
|
||||
if(webRequest.EmulateBrowser)
|
||||
client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent);
|
||||
else
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "Jackett/" + configService.GetVersion());
|
||||
HttpResponseMessage response = null;
|
||||
var request = new HttpRequestMessage();
|
||||
request.Headers.ExpectContinue = false;
|
||||
request.RequestUri = new Uri(webRequest.Url);
|
||||
|
||||
if (request.Headers != null)
|
||||
if (webRequest.Headers != null)
|
||||
{
|
||||
foreach (var header in request.Headers)
|
||||
foreach (var header in webRequest.Headers)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
if (header.Key != "Content-Type")
|
||||
{
|
||||
request.Headers.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (request.Type == RequestType.POST)
|
||||
if (!string.IsNullOrEmpty(webRequest.RawBody))
|
||||
{
|
||||
var content = new FormUrlEncodedContent(request.PostData);
|
||||
response = await client.PostAsync(request.Url, content);
|
||||
var type = webRequest.Headers.Where(h => h.Key == "Content-Type").Cast<KeyValuePair<string,string>?>().FirstOrDefault();
|
||||
if (type.HasValue)
|
||||
{
|
||||
var str = new StringContent(webRequest.RawBody);
|
||||
str.Headers.Remove("Content-Type");
|
||||
str.Headers.Add("Content-Type", type.Value.Value);
|
||||
request.Content = str;
|
||||
}
|
||||
else
|
||||
request.Content = new StringContent(webRequest.RawBody);
|
||||
request.Method = HttpMethod.Post;
|
||||
}
|
||||
else if (webRequest.Type == RequestType.POST)
|
||||
{
|
||||
request.Content = new FormUrlEncodedContent(webRequest.PostData);
|
||||
request.Method = HttpMethod.Post;
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await client.GetAsync(request.Url);
|
||||
request.Method = HttpMethod.Get;
|
||||
}
|
||||
|
||||
response = await client.SendAsync(request);
|
||||
|
||||
var result = new WebClientByteResult();
|
||||
result.Content = await response.Content.ReadAsByteArrayAsync();
|
||||
if (response.Headers.Location != null)
|
||||
@@ -100,18 +128,27 @@ namespace Jackett.Utils.Clients
|
||||
// Pull it out manually ignoring the expiry date then set it manually
|
||||
// http://stackoverflow.com/questions/14681144/httpclient-not-storing-cookies-in-cookiecontainer
|
||||
IEnumerable<string> cookieHeaders;
|
||||
var responseCookies = new List<Tuple<string, string>>();
|
||||
if (response.Headers.TryGetValues("set-cookie", out cookieHeaders))
|
||||
{
|
||||
var cookieBuilder = new StringBuilder();
|
||||
foreach (var c in cookieHeaders)
|
||||
foreach (var value in cookieHeaders)
|
||||
{
|
||||
cookieBuilder.AppendFormat("{0} ", c.Substring(0, c.IndexOf(';') + 1));
|
||||
var nameSplit = value.IndexOf('=');
|
||||
if (nameSplit > -1)
|
||||
{
|
||||
responseCookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
result.Cookies = cookieBuilder.ToString().TrimEnd();
|
||||
var cookieBuilder = new StringBuilder();
|
||||
foreach (var cookieGroup in responseCookies.GroupBy(c => c.Item1))
|
||||
{
|
||||
cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2);
|
||||
}
|
||||
result.Cookies = cookieBuilder.ToString().Trim();
|
||||
}
|
||||
|
||||
ServerUtil.ResureRedirectIsFullyQualified(request, result);
|
||||
ServerUtil.ResureRedirectIsFullyQualified(webRequest, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -76,12 +76,16 @@ namespace Jackett.Utils.Clients
|
||||
}
|
||||
else
|
||||
{
|
||||
if (request.PostData != null && request.PostData.Count() > 0)
|
||||
if (!string.IsNullOrEmpty(request.RawBody))
|
||||
{
|
||||
logger.Debug("UnixLibCurlWebClient: Posting " + request.RawBody);
|
||||
}
|
||||
else if (request.PostData != null && request.PostData.Count() > 0)
|
||||
{
|
||||
logger.Debug("UnixLibCurlWebClient: Posting " + StringUtil.PostDataFromDict(request.PostData));
|
||||
}
|
||||
|
||||
response = await CurlHelper.PostAsync(request.Url, request.PostData, request.Cookies, request.Referer);
|
||||
response = await CurlHelper.PostAsync(request.Url, request.PostData, request.Cookies, request.Referer, request.RawBody);
|
||||
}
|
||||
|
||||
var result = new WebClientByteResult()
|
||||
|
@@ -16,13 +16,15 @@ namespace Jackett.Utils.Clients
|
||||
{
|
||||
public class UnixSafeCurlWebClient : IWebClient
|
||||
{
|
||||
private IProcessService processService;
|
||||
private Logger logger;
|
||||
IProcessService processService;
|
||||
Logger logger;
|
||||
IConfigurationService configService;
|
||||
|
||||
public UnixSafeCurlWebClient(IProcessService p, Logger l)
|
||||
public UnixSafeCurlWebClient(IProcessService p, Logger l, IConfigurationService c)
|
||||
{
|
||||
processService = p;
|
||||
logger = l;
|
||||
configService = c;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
@@ -49,7 +51,11 @@ namespace Jackett.Utils.Clients
|
||||
{
|
||||
var args = new StringBuilder();
|
||||
args.AppendFormat("--url \"{0}\" ", request.Url);
|
||||
args.AppendFormat("-i -sS --user-agent \"{0}\" ", BrowserUtil.ChromeUserAgent);
|
||||
|
||||
if (request.EmulateBrowser)
|
||||
args.AppendFormat("-i -sS --user-agent \"{0}\" ", BrowserUtil.ChromeUserAgent);
|
||||
else
|
||||
args.AppendFormat("-i -sS --user-agent \"{0}\" ", "Jackett/" + configService.GetVersion());
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Cookies))
|
||||
{
|
||||
@@ -61,7 +67,11 @@ namespace Jackett.Utils.Clients
|
||||
args.AppendFormat("--referer \"{0}\" ", request.Referer);
|
||||
}
|
||||
|
||||
if (request.PostData != null && request.PostData.Count() > 0)
|
||||
if (!string.IsNullOrEmpty(request.RawBody))
|
||||
{
|
||||
var postString = StringUtil.PostDataFromDict(request.PostData);
|
||||
args.AppendFormat("--data \"{0}\" ", request.RawBody.Replace("\"", "\\\""));
|
||||
} else if (request.PostData != null && request.PostData.Count() > 0)
|
||||
{
|
||||
var postString = StringUtil.PostDataFromDict(request.PostData);
|
||||
args.AppendFormat("--data \"{0}\" ", postString);
|
||||
@@ -92,6 +102,9 @@ namespace Jackett.Utils.Clients
|
||||
throw new Exception("Invalid response");
|
||||
var headers = stdout.Substring(0, headSplit);
|
||||
var headerCount = 0;
|
||||
var cookieBuilder = new StringBuilder();
|
||||
var cookies = new List<Tuple<string, string>>();
|
||||
|
||||
foreach (var header in headers.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (headerCount == 0)
|
||||
@@ -109,11 +122,11 @@ namespace Jackett.Utils.Clients
|
||||
switch (name)
|
||||
{
|
||||
case "set-cookie":
|
||||
var cookieDataSplit = value.IndexOf(';');
|
||||
if (cookieDataSplit > 0)
|
||||
var nameSplit = value.IndexOf('=');
|
||||
if (nameSplit > -1)
|
||||
{
|
||||
result.Cookies += value.Substring(0, cookieDataSplit + 1) + " ";
|
||||
}//Location
|
||||
cookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') + 1)));
|
||||
}
|
||||
break;
|
||||
case "location":
|
||||
result.RedirectingTo = value.Trim();
|
||||
@@ -124,6 +137,12 @@ namespace Jackett.Utils.Clients
|
||||
headerCount++;
|
||||
}
|
||||
|
||||
foreach (var cookieGroup in cookies.GroupBy(c => c.Item1))
|
||||
{
|
||||
cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2);
|
||||
}
|
||||
|
||||
result.Cookies = cookieBuilder.ToString().Trim();
|
||||
result.Content = new byte[outputData.Length - (headSplit + 3)];
|
||||
var dest = 0;
|
||||
for (int i = headSplit + 4; i < outputData.Length; i++)
|
||||
|
@@ -14,6 +14,7 @@ namespace Jackett.Utils.Clients
|
||||
PostData = new List<KeyValuePair<string, string>>();
|
||||
Type = RequestType.GET;
|
||||
Headers = new Dictionary<string, string>();
|
||||
EmulateBrowser = true;
|
||||
}
|
||||
|
||||
public WebRequest(string url)
|
||||
@@ -22,6 +23,7 @@ namespace Jackett.Utils.Clients
|
||||
Type = RequestType.GET;
|
||||
Url = url;
|
||||
Headers = new Dictionary<string, string>();
|
||||
EmulateBrowser = true;
|
||||
}
|
||||
|
||||
public string Url { get; set; }
|
||||
@@ -29,6 +31,8 @@ namespace Jackett.Utils.Clients
|
||||
public string Cookies { get; set; }
|
||||
public string Referer { get; set; }
|
||||
public RequestType Type { get; set; }
|
||||
public string RawBody { get; set; }
|
||||
public bool EmulateBrowser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Warning this is only implemented on HTTPWebClient currently!
|
||||
|
Reference in New Issue
Block a user