Compare commits

...

31 Commits

Author SHA1 Message Date
flightlevel
baf44314e9 Merge pull request #278 from flightlevel/transmithenet
Add Transmithe.Net tracker
2016-03-19 22:43:21 +11:00
flightlevel
29ef28b6d7 Add Transmithe.Net tracker
Add Transmithe.Net tracker
2016-03-19 22:40:00 +11:00
flightlevel
86dad52919 Merge pull request #277 from flightlevel/imdbid--match
Fix IMDB Matching
2016-03-19 22:32:56 +11:00
flightlevel
6ff05656ef Fix IMDB Matching
Comparing number to string was failing when imdb id had a leading zero
2016-03-19 19:13:06 +11:00
flightlevel
71c195cafb Merge pull request #273 from flightlevel/freshon--refactor
Freshon: Use AngleSharp for parsing
2016-03-17 20:56:29 +11:00
flightlevel
dda0ae2485 Freshon: Use AngleSharp for parsing
Freshon: Use AngleSharp for parsing
2016-03-17 20:52:29 +11:00
flightlevel
69dc63c726 Merge pull request #272 from flightlevel/anglesharp-update
Update Anglesharp
2016-03-17 20:51:02 +11:00
flightlevel
ee65721da1 Update Anglesharp
Update Anglesharp
2016-03-17 20:40:17 +11:00
Azerelat
8ffb91f414 Merge pull request #264 from lowet84/master
Updated encryption service for better use with Docker
2016-03-13 10:46:53 +00:00
Fredrik Löwenhamn
50d931b4fb Updated encryptioon service for better use with Docker 2016-03-04 10:05:47 +01:00
flightlevel
6f475b18f3 Merge pull request #259 from flightlevel/ipturl
Fix IPTorrents url encoding
2016-02-27 21:13:30 +11:00
flightlevel
782211d06a Fix IPTorrents url encoding
Fix IPTorrents url encoding
Issue https://github.com/Jackett/Jackett/issues/256
2016-02-27 21:09:19 +11:00
Azerelat
4f5d7a3d54 Make category mapping a little less confusing #255 2016-02-24 18:40:16 +00:00
flightlevel
f26f2d6f25 Merge pull request #249 from flightlevel/tehconnection
TehConnection: Attempt to fix cookie expiration
2016-02-17 23:36:04 +11:00
flightlevel
6ccbfd6443 TehConnection: Attempt to fix cookie expiration
TehConnection: Attempt to fix cookie expiration
2016-02-17 23:30:04 +11:00
flightlevel
c896ed8238 Merge pull request #248 from flightlevel/danishbits
DanishBits: Fix publish time
2016-02-17 22:17:00 +11:00
flightlevel
1879ed89df DanishBits: Fix publish time
DanishBits: Fix publish time
2016-02-17 22:10:36 +11:00
flightlevel
11f99a44d3 Merge pull request #247 from flightlevel/ilovetorrents
ILoveTorrents: Add to readme
2016-02-16 19:42:08 +11:00
flightlevel
f8fcf2fb79 ILoveTorrents: Add to readme
ILoveTorrents: Add to readme
2016-02-16 19:32:18 +11:00
flightlevel
c36a3f558a Merge pull request #246 from lowet84/master
Fixed a bug in the download link.
2016-02-16 19:22:10 +11:00
Fredrik Löwenhamn
07a88919b4 Fixed a bug in the download link.
Added more categories.
2016-02-16 08:02:12 +01:00
Azerelat
d02cb3fefc Merge pull request #245 from lowet84/master
Added support for ILoveTorrents.me
2016-02-15 20:22:45 +00:00
Fredrik Löwenhamn
f05eca3a9f Added support for ILoveTorrents.me 2016-02-15 13:10:06 +01:00
flightlevel
ccc2441a55 Merge pull request #243 from flightlevel/scenetime
SceneTime: Add category mapping and fix search
2016-02-14 15:19:29 +11:00
flightlevel
5aaa402287 SceneTime: Add category mapping and fix search
SceneTime: Add category mapping and fix search
2016-02-14 15:15:09 +11:00
flightlevel
97849dfcaf Merge pull request #242 from flightlevel/scenetime
SceneTime: Fix Column parsing
2016-02-13 17:01:23 +11:00
flightlevel
f2a899eea3 SceneTime: Fix Column parsing
SceneTime: Column numbers seem to be related to user settings, use
column names instead. Add category mapping support
2016-02-13 16:55:23 +11:00
flightlevel
80686c81ee Merge pull request #236 from flightlevel/bitmetvinfo
BitMeTv: Add instructions
2016-02-07 16:49:42 +11:00
flightlevel
189483b2b7 BitMeTv: Add instructions
BitMeTv: Add instructions to turn on SSL
2016-02-07 16:39:20 +11:00
flightlevel
e7cc147121 Merge pull request #235 from flightlevel/scenetimefix
Scenetime: Fix parsing
2016-02-07 16:38:18 +11:00
flightlevel
73f044c0f2 Scenetime: Fix parsing
Scenetime: Fix parsing as per
https://github.com/Jackett/Jackett/issues/231#issuecomment-180289081
2016-02-07 16:22:33 +11:00
19 changed files with 662 additions and 125 deletions

View File

@@ -35,6 +35,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* HD-Space
* HD-Torrents
* Hounddawgs
* ILoveTorrents
* Immortalseed
* IPTorrents
* MoreThanTV

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -436,43 +436,23 @@ namespace Jackett.Indexers
}
}
protected void AddCategoryMapping(string trackerCategory, int newznabCategory)
protected void AddCategoryMapping(string trackerCategory, TorznabCategory newznabCategory)
{
categoryMapping.Add(new CategoryMapping(trackerCategory, newznabCategory));
categoryMapping.Add(new CategoryMapping(trackerCategory, newznabCategory.ID));
if (!TorznabCaps.Categories.Contains(newznabCategory))
TorznabCaps.Categories.Add(newznabCategory);
}
protected void AddCategoryMapping(int trackerCategory, TorznabCategory newznabCategory)
{
categoryMapping.Add(new CategoryMapping(trackerCategory.ToString(), newznabCategory.ID));
if (!TorznabCaps.Categories.Contains(newznabCategory))
TorznabCaps.Categories.Add(newznabCategory);
}
protected void AddCategoryMapping(string trackerCategory, TorznabCategory newznabCategory)
{
categoryMapping.Add(new CategoryMapping(trackerCategory.ToString(), newznabCategory.ID));
if (!TorznabCaps.Categories.Contains(newznabCategory))
TorznabCaps.Categories.Add(newznabCategory);
}
protected void AddCategoryMapping(int trackerCategory, int newznabCategory)
{
categoryMapping.Add(new CategoryMapping(trackerCategory.ToString(), newznabCategory));
AddCategoryMapping(trackerCategory.ToString(), newznabCategory);
}
protected void AddMultiCategoryMapping(TorznabCategory newznabCategory, params int[] trackerCategories)
{
foreach (var trackerCat in trackerCategories)
{
categoryMapping.Add(new CategoryMapping(trackerCat.ToString(), newznabCategory.ID));
}
}
protected void AddMultiCategoryMapping(int trackerCategory, params TorznabCategory[] newznabCategories)
{
foreach (var newznabCat in newznabCategories)
{
categoryMapping.Add(new CategoryMapping(trackerCategory.ToString(), newznabCat.ID));
AddCategoryMapping(trackerCat, newznabCategory);
}
}

View File

@@ -42,7 +42,7 @@ namespace Jackett.Indexers
client: c,
logger: l,
p: ps,
configData: new ConfigurationDataCaptchaLogin())
configData: new ConfigurationDataCaptchaLogin("Ensure that you have the 'Force SSL' option set to 'yes' in your profile on the BitMeTv webpage."))
{
}

View File

@@ -1,8 +1,6 @@
using CsQuery;
using Jackett.Indexers;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
using Newtonsoft.Json.Linq;
using NLog;
@@ -10,14 +8,9 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI.WebControls;
using CsQuery.ExtensionMethods;
using Jackett.Models.IndexerConfig;
@@ -38,7 +31,7 @@ namespace Jackett.Indexers
: base(name: "DanishBits",
description: "A danish closed torrent tracker",
link: "https://danishbits.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
caps: new TorznabCapabilities(),
manager: i,
client: c,
logger: l,
@@ -151,6 +144,13 @@ namespace Jackett.Indexers
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 3, 5, DayOfWeek.Sunday);
TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 10, 5, DayOfWeek.Sunday);
TimeSpan delta = new TimeSpan(1, 0, 0);
TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition);
TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment };
TimeZoneInfo denmarkTz = TimeZoneInfo.CreateCustomTimeZone("Denmark Time", new TimeSpan(1, 0, 0), "(GMT+01:00) Denmark Time", "Denmark Time", "Denmark DST", adjustments);
var releasesPerPage = 100;
var releases = new List<ReleaseInfo>();
@@ -244,9 +244,8 @@ namespace Jackett.Indexers
var addedElement = qRow.Find("span.time").FirstElement();
var addedStr = addedElement.GetAttribute("title");
release.PublishDate = DateTime.ParseExact(addedStr, "MMM dd yyyy, HH:mm",
CultureInfo.InvariantCulture);
release.PublishDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(addedStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture), denmarkTz).ToLocalTime();
var columns = qRow.Children();
var seedersElement = columns.Reverse().Skip(1).First();
release.Seeders = int.Parse(seedersElement.InnerText);

View File

@@ -1,6 +1,4 @@
using CsQuery;
using Jackett.Indexers;
using Jackett.Models;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
@@ -10,14 +8,10 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI.WebControls;
using Jackett.Models.IndexerConfig;
using AngleSharp;
namespace Jackett.Indexers
{
@@ -42,7 +36,7 @@ namespace Jackett.Indexers
client: c,
logger: l,
p: ps,
configData: new ConfigurationDataBasicLogin())
configData: new ConfigurationDataBasicLogin("For best results, change the 'Torrents per page' setting to 100 in your profile on the FreshOn webpage."))
{
}
@@ -60,15 +54,32 @@ namespace Jackett.Indexers
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout.php"), () =>
{
CQ dom = response.Content;
var messageEl = dom[".error_text"];
var errorMessage = messageEl.Text().Trim();
var parser = new AngleSharp.Parser.Html.HtmlParser();
var document = parser.Parse(response.Content);
var messageEl = document.QuerySelector(".error_text");
var errorMessage = messageEl.TextContent.Trim();
throw new ExceptionWithConfigData(errorMessage, configData);
});
return IndexerConfigurationStatus.RequiresTesting;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
string Url;
if (string.IsNullOrEmpty(query.GetQueryString()))
Url = SearchUrl;
else
{
Url = $"{SearchUrl}?search={HttpUtility.UrlEncode(query.GetQueryString())}&cat=0";
}
var response = await RequestStringWithCookiesAndRetry(Url);
List<ReleaseInfo> releases = ParseResponse(response.Content);
return releases;
}
private List<ReleaseInfo> ParseResponse(string htmlResponse)
{
TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday);
TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday);
@@ -77,53 +88,40 @@ namespace Jackett.Indexers
TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment };
TimeZoneInfo romaniaTz = TimeZoneInfo.CreateCustomTimeZone("Romania Time", new TimeSpan(2, 0, 0), "(GMT+02:00) Romania Time", "Romania Time", "Romania Daylight Time", adjustments);
var releases = new List<ReleaseInfo>();
string episodeSearchUrl;
List<ReleaseInfo> releases = new List<ReleaseInfo>();
if (string.IsNullOrEmpty(query.GetQueryString()))
episodeSearchUrl = SearchUrl;
else
{
episodeSearchUrl = $"{SearchUrl}?search={HttpUtility.UrlEncode(query.GetQueryString())}&cat=0";
}
var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl);
try
{
CQ dom = results.Content;
var parser = new AngleSharp.Parser.Html.HtmlParser();
var document = parser.Parse(htmlResponse);
var rows = document.QuerySelectorAll("#highlight > tbody > tr:not(:First-child)");
var rows = dom["#highlight > tbody > tr"];
foreach (var row in rows.Skip(1))
foreach (var row in rows)
{
var release = new ReleaseInfo();
var qRow = row.Cq();
var qLink = qRow.Find("a.torrent_name_link").First();
var linkNameElement = row.QuerySelector("a.torrent_name_link");
release.Title = linkNameElement.GetAttribute("title");
release.Description = release.Title;
release.Guid = new Uri(SiteLink + linkNameElement.GetAttribute("href"));
release.Comments = release.Guid;
release.Link = new Uri(SiteLink + row.QuerySelector("td.table_links > a").GetAttribute("href"));
release.Category = TvCategoryParser.ParseTvShowQuality(release.Title);
release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td.table_seeders").TextContent.Trim());
release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td.table_leechers").TextContent.Trim()) + release.Seeders;
release.Size = ReleaseInfo.GetBytes(row.QuerySelector("td.table_size").TextContent);
release.MinimumRatio = 1;
release.MinimumSeedTime = 172800;
release.Title = qLink.Attr("title");
release.Description = release.Title;
release.Guid = new Uri(SiteLink + qLink.Attr("href"));
release.Comments = release.Guid;
release.Link = new Uri(SiteLink + qRow.Find("td.table_links > a").First().Attr("href"));
release.Category = TvCategoryParser.ParseTvShowQuality(release.Title);
release.Seeders = ParseUtil.CoerceInt(qRow.Find("td.table_seeders").Text().Trim());
release.Peers = ParseUtil.CoerceInt(qRow.Find("td.table_leechers").Text().Trim()) + release.Seeders;
var sizeStr = qRow.Find("td.table_size")[0].Cq().Text();
release.Size = ReleaseInfo.GetBytes(sizeStr);
DateTime pubDateRomania;
var dateString = qRow.Find("td.table_added").Text().Trim();
var dateString = row.QuerySelector("td.table_added").TextContent.Trim();
if (dateString.StartsWith("Today "))
{ pubDateRomania = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateString.Split(' ')[1]); }
{ pubDateRomania = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateString.Split(' ')[1]); }
else if (dateString.StartsWith("Yesterday "))
{ pubDateRomania = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateString.Split(' ')[1]) - TimeSpan.FromDays(1); }
{ pubDateRomania = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateString.Split(' ')[1]) - TimeSpan.FromDays(1); }
else
{ pubDateRomania = DateTime.SpecifyKind(DateTime.ParseExact(dateString, "d-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); }
{ pubDateRomania = DateTime.SpecifyKind(DateTime.ParseExact(dateString, "d-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); }
DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(pubDateRomania, romaniaTz);
release.PublishDate = pubDateUtc.ToLocalTime();
@@ -133,7 +131,7 @@ namespace Jackett.Indexers
}
catch (Exception ex)
{
OnParseError(results.Content, ex);
OnParseError(htmlResponse, ex);
}
return releases;

View File

@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CsQuery;
using CsQuery.ExtensionMethods.Internal;
using Jackett.Models;
using Jackett.Models.IndexerConfig;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
using Newtonsoft.Json.Linq;
using NLog;
namespace Jackett.Indexers
{
// ReSharper disable once InconsistentNaming
public class ILoveTorrents : BaseIndexer, IIndexer
{
private string BrowseUrl => SiteLink + "browse.php";
private string LoginUrl => SiteLink + "takelogin.php";
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public ILoveTorrents(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "ILoveTorrents",
description: "ILT",
link: "https://www.ilovetorrents.me/",
caps: new TorznabCapabilities(),
manager: i,
client: wc,
logger: l,
p: ps,
configData: new ConfigurationDataBasicLogin())
{
AddCategoryMapping(85, TorznabCatType.Movies3D);
AddCategoryMapping(23, TorznabCatType.TVAnime);
AddCategoryMapping(24, TorznabCatType.BooksEbook);
AddCategoryMapping(4, TorznabCatType.PCGames);
AddCategoryMapping(38, TorznabCatType.ConsolePS3);
AddCategoryMapping(38, TorznabCatType.ConsolePS4);
AddCategoryMapping(38, TorznabCatType.ConsolePSP);
AddCategoryMapping(43, TorznabCatType.ConsoleWii);
AddCategoryMapping(43, TorznabCatType.ConsoleWiiU);
AddCategoryMapping(12, TorznabCatType.ConsoleXBOX360DLC);
AddCategoryMapping(12, TorznabCatType.ConsoleXbox);
AddCategoryMapping(12, TorznabCatType.ConsoleXbox360);
AddCategoryMapping(12, TorznabCatType.ConsoleXboxOne);
AddCategoryMapping(6, TorznabCatType.Audio);
AddCategoryMapping(7, TorznabCatType.TV);
AddCategoryMapping(40, TorznabCatType.TVSD);
AddCategoryMapping(8, TorznabCatType.TVHD);
AddCategoryMapping(9, TorznabCatType.XXX);
AddCategoryMapping(11, TorznabCatType.XXXDVD);
AddCategoryMapping(10, TorznabCatType.XXXx264);
AddCategoryMapping(80, TorznabCatType.MoviesBluRay);
AddCategoryMapping(20, TorznabCatType.MoviesDVD);
AddCategoryMapping(41, TorznabCatType.MoviesHD);
AddCategoryMapping(19, TorznabCatType.Movies);
}
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "returnto", "/" },
{ "login", "Log in!" }
};
var loginPage = await RequestStringWithCookies(SiteLink, string.Empty);
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, SiteLink, SiteLink);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
{
CQ dom = result.Content;
var messageEl = dom["body > div"].First();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, configData);
});
return IndexerConfigurationStatus.RequiresTesting;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var searchString = query.GetQueryString();
var searchUrl = BrowseUrl;
var trackerCats = MapTorznabCapsToTrackers(query);
var queryCollection = new NameValueCollection();
// Tracker can only search OR return things in categories
if (!string.IsNullOrWhiteSpace(searchString))
{
queryCollection.Add("search", searchString);
queryCollection.Add("cat", "0");
}
else
{
foreach (var cat in MapTorznabCapsToTrackers(query))
{
queryCollection.Add("c" + cat, "1");
}
queryCollection.Add("incldead", "0");
}
searchUrl += "?" + queryCollection.GetQueryString();
await ProcessPage(releases, searchUrl);
return releases;
}
private async Task ProcessPage(List<ReleaseInfo> releases, string searchUrl)
{
var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl);
var results = response.Content;
try
{
CQ dom = results;
var rows = dom[".koptekst tr"];
foreach (var row in rows.Skip(1))
{
var release = new ReleaseInfo();
var link = row.Cq().Find("td:eq(1) a:eq(0)").First();
release.Guid = new Uri(SiteLink + link.Attr("href"));
release.Comments = release.Guid;
release.Title = link.Text().Trim();
release.Description = release.Title;
// If we search an get no results, we still get a table just with no info.
if (string.IsNullOrWhiteSpace(release.Title))
{
break;
}
// Check if the release has been assigned a category
if (row.Cq().Find("td:eq(0) a").Length > 0)
{
var cat = row.Cq().Find("td:eq(0) a").First().Attr("href").Substring(15);
release.Category = MapTrackerCatToNewznab(cat);
}
var qLink = row.Cq().Find("td:eq(2) a").First();
release.Link = new Uri(SiteLink + qLink.Attr("href"));
var added = row.Cq().Find("td:eq(7)").First().Text().Trim();
var date = added.Substring(0, 10);
var time = added.Substring(12, 8);
var dateTime = date + time;
release.PublishDate = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime();
var sizeStr = row.Cq().Find("td:eq(8)").First().Text().Trim();
release.Size = ReleaseInfo.GetBytes(sizeStr);
release.Seeders = ParseUtil.CoerceInt(row.Cq().Find("td:eq(10)").First().Text().Trim());
release.Peers = ParseUtil.CoerceInt(row.Cq().Find("td:eq(11)").First().Text().Trim()) + release.Seeders;
releases.Add(release);
}
}
catch (Exception ex)
{
OnParseError(results, ex);
}
}
}
}

View File

@@ -165,7 +165,7 @@ namespace Jackett.Indexers
release.PublishDate = DateTimeUtil.FromTimeAgo(dateString);
var qLink = row.ChildElements.ElementAt(3).Cq().Children("a");
release.Link = new Uri(SiteLink + qLink.Attr("href").TrimStart('/'));
release.Link = new Uri(SiteLink + HttpUtility.UrlEncode(qLink.Attr("href").TrimStart('/')));
var sizeStr = row.ChildElements.ElementAt(5).Cq().Text();
release.Size = ReleaseInfo.GetBytes(sizeStr);

View File

@@ -7,14 +7,10 @@ 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.Text.RegularExpressions;
namespace Jackett.Indexers
{
@@ -34,13 +30,52 @@ namespace Jackett.Indexers
: base(name: "SceneTime",
description: "Always on time",
link: "https://www.scenetime.com/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
caps: new TorznabCapabilities(),
manager: i,
client: w,
logger: l,
p: ps,
configData: new ConfigurationDataBasicLogin())
configData: new ConfigurationDataBasicLogin("For best results, change the 'Torrents per page' setting to the maximum in your profile on the SceneTime webpage."))
{
AddCategoryMapping(1, TorznabCatType.MoviesSD);
AddCategoryMapping(3, TorznabCatType.MoviesDVD);
AddCategoryMapping(47, TorznabCatType.MoviesSD);
AddCategoryMapping(57, TorznabCatType.MoviesSD);
AddCategoryMapping(59, TorznabCatType.MoviesHD);
AddCategoryMapping(61, TorznabCatType.MoviesSD);
AddCategoryMapping(64, TorznabCatType.Movies3D);
AddCategoryMapping(80, TorznabCatType.MoviesForeign);
AddCategoryMapping(81, TorznabCatType.MoviesBluRay);
AddCategoryMapping(82, TorznabCatType.MoviesOther);
AddCategoryMapping(102, TorznabCatType.MoviesOther);
AddCategoryMapping(103, TorznabCatType.MoviesWEBDL);
AddCategoryMapping(105, TorznabCatType.Movies);
AddCategoryMapping(6, TorznabCatType.PCGames);
AddCategoryMapping(48, TorznabCatType.ConsoleXbox);
AddCategoryMapping(49, TorznabCatType.ConsolePSP);
AddCategoryMapping(50, TorznabCatType.ConsolePS3);
AddCategoryMapping(51, TorznabCatType.ConsoleWii);
AddCategoryMapping(55, TorznabCatType.ConsoleNDS);
AddCategoryMapping(107, TorznabCatType.ConsolePS4);
AddCategoryMapping(2, TorznabCatType.TVSD);
AddCategoryMapping(43, TorznabCatType.TV);
AddCategoryMapping(9, TorznabCatType.TVHD);
AddCategoryMapping(63, TorznabCatType.TV);
AddCategoryMapping(77, TorznabCatType.TVSD);
AddCategoryMapping(79, TorznabCatType.TVSport);
AddCategoryMapping(100, TorznabCatType.TVFOREIGN);
AddCategoryMapping(83, TorznabCatType.TVWEBDL);
AddCategoryMapping(5, TorznabCatType.PC0day);
AddCategoryMapping(7, TorznabCatType.Books);
AddCategoryMapping(52, TorznabCatType.PCMac);
AddCategoryMapping(65, TorznabCatType.BooksComics);
AddCategoryMapping(53, TorznabCatType.PC);
AddCategoryMapping(4, TorznabCatType.Audio);
AddCategoryMapping(11, TorznabCatType.AudioVideo);
}
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
@@ -62,23 +97,45 @@ namespace Jackett.Indexers
return IndexerConfigurationStatus.RequiresTesting;
}
private Dictionary<string, string> GetSearchFormData(string searchString)
{
return new Dictionary<string, string> {
{ "c2", "1" }, { "c43", "1" }, { "c9", "1" }, { "c63", "1" }, { "c77", "1" }, { "c100", "1" }, { "c101", "1" },
{ "cata", "yes" }, { "sec", "jax" },
{ "search", searchString}
};
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(query.GetQueryString()));
Dictionary<string, string> qParams = new Dictionary<string, string>();
qParams.Add("cata", "yes");
qParams.Add("sec", "jax");
List<string> catList = MapTorznabCapsToTrackers(query);
foreach (string cat in catList)
{
qParams.Add("c" + cat, "1");
}
if (!string.IsNullOrEmpty(query.SanitizedSearchTerm))
{
qParams.Add("search", query.GetQueryString());
}
var results = await PostDataWithCookiesAndRetry(SearchUrl, qParams);
List<ReleaseInfo> releases = ParseResponse(results.Content);
return releases;
}
public List<ReleaseInfo> ParseResponse(string htmlResponse)
{
List<ReleaseInfo> releases = new List<ReleaseInfo>();
try
{
CQ dom = results.Content;
CQ dom = htmlResponse;
List<string> headerColumns = dom["table[class*='movehere']"].First().Find("tbody > tr > td[class='cat_Head']").Select(x => x.Cq().Text()).ToList();
int categoryIndex = headerColumns.FindIndex(x => x.Equals("Type"));
int nameIndex = headerColumns.FindIndex(x => x.Equals("Name"));
int sizeIndex = headerColumns.FindIndex(x => x.Equals("Size"));
int seedersIndex = headerColumns.FindIndex(x => x.Equals("Seeders"));
int leechersIndex = headerColumns.FindIndex(x => x.Equals("Leechers"));
var rows = dom["tr.browse"];
foreach (var row in rows)
{
@@ -86,7 +143,12 @@ namespace Jackett.Indexers
release.MinimumRatio = 1;
release.MinimumSeedTime = 172800;
var descCol = row.ChildElements.ElementAt(1);
var categoryCol = row.ChildElements.ElementAt(categoryIndex);
string catLink = categoryCol.Cq().Find("a").Attr("href");
string catId = new Regex(@"\?cat=(\d*)").Match(catLink).Groups[1].ToString().Trim();
release.Category = MapTrackerCatToNewznab(catId);
var descCol = row.ChildElements.ElementAt(nameIndex);
var qDescCol = descCol.Cq();
var qLink = qDescCol.Find("a");
release.Title = qLink.Text();
@@ -98,19 +160,20 @@ namespace Jackett.Indexers
release.PublishDate = DateTimeUtil.FromTimeAgo(descCol.ChildNodes.Last().InnerText);
var sizeStr = row.ChildElements.ElementAt(5).Cq().Text();
var sizeStr = row.ChildElements.ElementAt(sizeIndex).Cq().Text();
release.Size = ReleaseInfo.GetBytes(sizeStr);
release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(6).Cq().Text().Trim());
release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text().Trim()) + release.Seeders;
release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(seedersIndex).Cq().Text().Trim());
release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(leechersIndex).Cq().Text().Trim()) + release.Seeders;
releases.Add(release);
}
}
catch (Exception ex)
{
OnParseError(results.Content, ex);
OnParseError(htmlResponse, ex);
}
return releases;
}
}

View File

@@ -1,5 +1,4 @@
using CsQuery;
using Jackett.Indexers;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils;
@@ -41,27 +40,35 @@ namespace Jackett.Indexers
Separate options with a space if using more than one option.<br>Filter options available:
<br><code>QualityEncodeOnly</code><br><code>FreeLeechOnly</code>"))
{
AddCategoryMapping(7, TorznabCatType.Movies);
AddCategoryMapping(7, TorznabCatType.MoviesForeign);
AddCategoryMapping(7, TorznabCatType.MoviesOther);
AddCategoryMapping(7, TorznabCatType.MoviesSD);
AddCategoryMapping(7, TorznabCatType.MoviesHD);
AddCategoryMapping(7, TorznabCatType.Movies3D);
AddCategoryMapping(7, TorznabCatType.MoviesBluRay);
AddCategoryMapping(7, TorznabCatType.MoviesDVD);
AddCategoryMapping(7, TorznabCatType.MoviesWEBDL);
AddCategoryMapping(1, TorznabCatType.Movies);
AddCategoryMapping(1, TorznabCatType.MoviesForeign);
AddCategoryMapping(1, TorznabCatType.MoviesOther);
AddCategoryMapping(1, TorznabCatType.MoviesSD);
AddCategoryMapping(1, TorznabCatType.MoviesHD);
AddCategoryMapping(1, TorznabCatType.Movies3D);
AddCategoryMapping(1, TorznabCatType.MoviesBluRay);
AddCategoryMapping(1, TorznabCatType.MoviesDVD);
AddCategoryMapping(1, TorznabCatType.MoviesWEBDL);
}
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
configData.LoadValuesFromJson(configJson);
await DoLogin();
return IndexerConfigurationStatus.RequiresTesting;
}
private async Task DoLogin()
{
var pairs = new Dictionary<string, string> {
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "keeplogged", "1" },
{ "login", "Log In!" }
};
var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, indexUrl, SiteLink);
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout.php"), () =>
@@ -70,11 +77,24 @@ namespace Jackett.Indexers
string errorMessage = "Unable to login to TehConnection";
throw new ExceptionWithConfigData(errorMessage, configData);
});
return IndexerConfigurationStatus.RequiresTesting;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var loggedInCheck = await RequestStringWithCookies(SearchUrl);
if (!loggedInCheck.Content.Contains("/logout.php"))
{
//Cookie appears to expire after a period of time or logging in to the site via browser
DateTime lastLoggedInCheck;
DateTime.TryParse(configData.LastLoggedInCheck.Value, out lastLoggedInCheck);
if (lastLoggedInCheck < DateTime.Now.AddMinutes(-15))
{
await DoLogin();
configData.LastLoggedInCheck.Value = DateTime.Now.ToString("o");
SaveConfig();
}
}
var releases = new List<ReleaseInfo>();
bool configFreeLeechOnly = configData.FilterString.Value.ToLowerInvariant().Contains("freeleechonly");
bool configQualityEncodeOnly = configData.FilterString.Value.ToLowerInvariant().Contains("qualityencodeonly");

View File

@@ -0,0 +1,133 @@
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.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
using AngleSharp.Parser.Html;
using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class TransmitheNet : BaseIndexer, IIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public TransmitheNet(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
: base(name: "TransmitTheNet",
description: " At Transmithe.net we will change the way you think about TV",
link: "https://transmithe.net/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: c,
logger: l,
p: ps,
configData: new ConfigurationDataBasicLogin("For best results, change the 'Torrents per page' setting to 100 in your profile on the TTN webpage."))
{
}
public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "keeplogged", "on" },
{ "login", "Login" }
};
CookieHeader = string.Empty;
var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, CookieHeader, true, null, LoginUrl);
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () =>
{
var parser = new HtmlParser();
var document = parser.Parse(response.Content);
var messageEl = document.QuerySelector("form > span[class='warning']");
var errorMessage = messageEl.TextContent.Trim();
throw new ExceptionWithConfigData(errorMessage, configData);
});
return IndexerConfigurationStatus.RequiresTesting;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
string Url;
if (string.IsNullOrEmpty(query.GetQueryString()))
Url = SearchUrl;
else
{
Url = $"{SearchUrl}?searchtext={HttpUtility.UrlEncode(query.GetQueryString())}";
}
var response = await RequestStringWithCookiesAndRetry(Url);
List<ReleaseInfo> releases = ParseResponse(response.Content);
return releases;
}
public List<ReleaseInfo> ParseResponse(string htmlResponse)
{
List<ReleaseInfo> releases = new List<ReleaseInfo>();
try
{
var parser = new HtmlParser();
var document = parser.Parse(htmlResponse);
var rows = document.QuerySelectorAll(".torrent_table > tbody > tr:not(:First-child)");
foreach (var row in rows)
{
var release = new ReleaseInfo();
string title = row.QuerySelector("a[data-src]").GetAttribute("data-src");
if (string.IsNullOrEmpty(title) || title == "0")
{
title = row.QuerySelector("a[data-src]").TextContent;
title = Regex.Replace(title, @"[\[\]\/]", "");
}
else
{
title = title.Remove(title.LastIndexOf("."));
}
release.Title = title;
release.Description = release.Title;
release.Guid = new Uri(SiteLink + row.QuerySelector("a[data-src]").GetAttribute("href"));
release.Comments = release.Guid;
release.Link = new Uri(SiteLink + row.QuerySelector("a[href*='action=download']").GetAttribute("href"));
release.Category = TvCategoryParser.ParseTvShowQuality(release.Title);
var timeAnchor = row.QuerySelector("span[class='time']");
release.PublishDate = DateTime.ParseExact(timeAnchor.GetAttribute("title"), "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);
release.Seeders = ParseUtil.CoerceInt(timeAnchor.ParentElement.NextElementSibling.NextElementSibling.TextContent.Trim());
release.Peers = ParseUtil.CoerceInt(timeAnchor.ParentElement.NextElementSibling.NextElementSibling.NextElementSibling.TextContent.Trim()) + release.Seeders;
release.Size = ReleaseInfo.GetBytes(timeAnchor.ParentElement.PreviousElementSibling.TextContent);
release.MinimumRatio = 1;
release.MinimumSeedTime = 172800;
releases.Add(release);
}
}
catch (Exception ex)
{
OnParseError(htmlResponse, ex);
}
return releases;
}
}
}

View File

@@ -58,8 +58,8 @@
</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="AngleSharp, Version=0.9.4.42449, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL">
<HintPath>..\packages\AngleSharp.0.9.4\lib\net45\AngleSharp.dll</HintPath>
<Reference Include="AngleSharp, Version=0.9.5.41771, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL">
<HintPath>..\packages\AngleSharp.0.9.5\lib\net45\AngleSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Autofac, Version=3.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
@@ -201,6 +201,7 @@
<Compile Include="Indexers\DanishBits.cs" />
<Compile Include="Indexers\Abnormal.cs" />
<Compile Include="Indexers\GFTracker.cs" />
<Compile Include="Indexers\ILoveTorrents.cs" />
<Compile Include="Indexers\RevolutionTT.cs" />
<Compile Include="Indexers\TehConnection.cs" />
<Compile Include="Indexers\Hounddawgs.cs" />
@@ -213,6 +214,7 @@
<Compile Include="Indexers\FileList.cs" />
<Compile Include="Indexers\Abstract\AvistazTracker.cs" />
<Compile Include="Indexers\FrenchADN.cs" />
<Compile Include="Indexers\TransmitheNet.cs" />
<Compile Include="Indexers\WiHD.cs" />
<Compile Include="Indexers\XSpeeds.cs" />
<Compile Include="Models\GitHub\Asset.cs" />
@@ -318,6 +320,7 @@
<Compile Include="Startup.cs" />
<Compile Include="Models\TorznabQuery.cs" />
<Compile Include="CurlHelper.cs" />
<Compile Include="Utils\StringCipher.cs" />
<Compile Include="Utils\StringUtil.cs" />
<Compile Include="Utils\TorznabCapsUtil.cs" />
<Compile Include="Utils\Clients\UnixSafeCurlWebClient.cs" />
@@ -478,6 +481,9 @@
<Content Include="Content\logos\hdtorrents.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\logos\ilovetorrents.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\logos\immortalseed.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -571,6 +577,9 @@
<Content Include="Content\logos\torrentleech.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\logos\transmithenet.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\logos\tvchaosuk.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View File

@@ -11,6 +11,7 @@ namespace Jackett.Models.IndexerConfig
{
public StringItem Username { get; private set; }
public StringItem Password { get; private set; }
public HiddenItem LastLoggedInCheck { get; private set; }
public DisplayItem FilterExample { get; private set; }
public StringItem FilterString { get; private set; }
@@ -18,6 +19,7 @@ namespace Jackett.Models.IndexerConfig
{
Username = new StringItem { Name = "Username" };
Password = new StringItem { Name = "Password" };
LastLoggedInCheck = new HiddenItem { Name = "LastLoggedInCheck" };
FilterExample = new DisplayItem(FilterInstructions)
{
Name = ""

View File

@@ -18,13 +18,17 @@ namespace Jackett.Models.IndexerConfig
public HiddenItem CaptchaCookie { get; private set; }
public ConfigurationDataCaptchaLogin()
public DisplayItem Instructions { get; private set; }
/// <param name="instructionMessageOptional">Enter any instructions the user will need to setup the tracker</param>
public ConfigurationDataCaptchaLogin(string instructionMessageOptional = null)
{
Username = new StringItem { Name = "Username" };
Password = new StringItem { Name = "Password" };
CaptchaImage = new ImageItem { Name = "Captcha Image" };
CaptchaText = new StringItem { Name = "Captcha Text" };
CaptchaCookie = new HiddenItem("") { Name = "Captcha Cookie" };
Instructions = new DisplayItem(instructionMessageOptional) { Name = "" };
}
}
}

View File

@@ -6,6 +6,7 @@ using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Jackett.Utils;
namespace Jackett.Services
{
@@ -18,6 +19,7 @@ namespace Jackett.Services
public class ProtectionService : IProtectionService
{
DataProtectionScope PROTECTION_SCOPE = DataProtectionScope.LocalMachine;
private const string JACKETT_KEY = "JACKETT_KEY";
const string APPLICATION_KEY = "Dvz66r3n8vhTGip2/quiw5ISyM37f7L2iOdupzdKmzkvXGhAgQiWK+6F+4qpxjPVNks1qO7LdWuVqRlzgLzeW8mChC6JnBMUS1Fin4N2nS9lh4XPuCZ1che75xO92Nk2vyXUo9KSFG1hvEszAuLfG2Mcg1r0sVyVXd2gQDU/TbY=";
IServerService serverService;
@@ -34,6 +36,34 @@ namespace Jackett.Services
}
public string Protect(string plainText)
{
var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY);
if (jackettKey == null)
{
return ProtectDefaultMethod(plainText);
}
else
{
return ProtectUsingKey(plainText, jackettKey);
}
}
public string UnProtect(string plainText)
{
var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY);
if (jackettKey == null)
{
return UnProtectDefaultMethod(plainText);
}
else
{
return UnProtectUsingKey(plainText, jackettKey);
}
}
private string ProtectDefaultMethod(string plainText)
{
if (string.IsNullOrEmpty(plainText))
return string.Empty;
@@ -72,7 +102,7 @@ namespace Jackett.Services
return Convert.ToBase64String(protectedBytes);
}
public string UnProtect(string plainText)
private string UnProtectDefaultMethod(string plainText)
{
if (string.IsNullOrEmpty(plainText))
return string.Empty;
@@ -111,6 +141,16 @@ namespace Jackett.Services
return Encoding.UTF8.GetString(unprotectedBytes);
}
private string ProtectUsingKey(string plainText, string key)
{
return StringCipher.Encrypt(plainText, key);
}
private string UnProtectUsingKey(string plainText, string key)
{
return StringCipher.Decrypt(plainText, key);
}
public void Protect<T>(T obj)
{
var type = obj.GetType();

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Utils
{
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
}

View File

@@ -74,7 +74,7 @@ namespace Jackett.Utils
// Filter out releases that do have a valid imdb ID, that is not equal to the one we're searching for.
return
results.Where(
result => !result.Imdb.HasValue || result.Imdb.Value == 0 || ("tt" + result.Imdb.Value).Equals(imdb));
result => !result.Imdb.HasValue || result.Imdb.Value == 0 || ("tt" + result.Imdb.Value.ToString("D7")).Equals(imdb));
}
private static string CleanTitle(string title)

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AngleSharp" version="0.9.4" targetFramework="net45" />
<package id="AngleSharp" version="0.9.5" targetFramework="net45" />
<package id="Autofac" version="3.5.2" targetFramework="net45" />
<package id="Autofac.Owin" version="3.1.0" targetFramework="net45" />
<package id="Autofac.WebApi" version="3.1.0" targetFramework="net45" />