Compare commits

...

13 Commits

Author SHA1 Message Date
Auggie
0884ac92ff Bump to 2.3.2 2025-12-29 05:10:15 +01:00
Bogdan
9508329b99 Fixed: (AB) Prevent false positives parsing seasons for "No. 8" 2025-12-28 21:22:15 +01:00
Bogdan
15a03007d9 Fixed: (Shazbat) More fixes to login form and parsing details 2025-12-28 21:14:13 +01:00
Auggie
b188746f1a Fixed: (Shazbat) Update login form and parsing details 2025-12-21 19:31:18 +01:00
Robin Dadswell
ed3b25b3d6 chore: updated build images 2025-11-14 23:14:55 +00:00
Robin Dadswell
c006079ce6 bump to 2.3.1 2025-11-14 22:58:29 +00:00
Mark McDowall
9437ff9498 Add private IPv6 networks
(cherry picked from commit 52972e7efcce800560cbbaa64f5f76aaef6cbe77)
2025-11-10 09:26:45 +00:00
bakerboy448
e4fb36e08f Bump to 2.3.0 2025-10-30 05:51:48 -05:00
Mark McDowall
ff22fdf7d3 Set known networks to RFC 1918 ranges during startup
(cherry picked from commit d10107739b9ed6a50165e5dd1dfae15c7e8aea56)
2025-10-29 23:42:00 +00:00
Polgonite
b3d46465ae Fixed: qBittorrent /login API success check 2025-10-29 17:59:58 -05:00
bakerboy448
eb57d20545 Bump to 2.2.0 2025-10-25 14:42:07 -05:00
bakerboy448
775b716c0f Fixed:(RuTracker) fix for Anime S01nd Episode N of N or N+N of N+N
Based on Jackett 5b712189fc55470dc94b56ea0d764e123e2dc432
2025-10-20 18:19:42 -05:00
bakerboy448
f7f3648dac Bump to 2.1.5 2025-10-13 19:42:22 -05:00
6 changed files with 40 additions and 28 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '2.1.4'
majorVersion: '2.3.2'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
@@ -18,9 +18,9 @@ variables:
dotnetVersion: '8.0.405'
nodeVersion: '20.X'
innoVersion: '6.2.2'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-22.04'
macImage: 'macOS-13'
windowsImage: 'windows-2025'
linuxImage: 'ubuntu-24.04'
macImage: 'macOS-15'
trigger:
branches:

View File

@@ -424,8 +424,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
catch (HttpException ex)
{
_logger.Debug("qbitTorrent authentication failed.");
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
_logger.Debug(ex, "qbitTorrent authentication failed.");
if (ex.Response.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
{
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.", ex);
}
@@ -437,9 +437,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
}
if (response.Content != "Ok.")
// returns "Fails." on bad login
if (response.Content.IsNotNullOrWhiteSpace() && response.Content != "Ok.")
{
// returns "Fails." on bad login
_logger.Debug("qbitTorrent authentication failed.");
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.");
}

View File

@@ -669,7 +669,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var advancedSeasonRegex = new Regex(@"\b(?:(?<season>\d+)(?:st|nd|rd|th) Season|Season (?<season>\d+))\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var seasonCharactersRegex = new Regex(@"(I{2,})$", RegexOptions.Compiled);
var seasonNumberRegex = new Regex(@"\b(?<!Part[- ._])(?<!\d[/])(?:S)?(?<season>[2-9])$", RegexOptions.Compiled);
var seasonNumberRegex = new Regex(@"\b(?<!(Part|No\.)[- ._])(?<!\d[/])(?<!\#)(?:S)?(?<season>[2-9])$", RegexOptions.Compiled);
foreach (var title in titles)
{

View File

@@ -1541,7 +1541,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (season != 0)
{
searchString += " Сезон: " + season;
searchString += " ТВ | Сезон: " + season;
}
parameters.Set("nm", searchString);
@@ -1712,6 +1712,8 @@ namespace NzbDrone.Core.Indexers.Definitions
private readonly Regex _tvTitleRusSeasonRegex = new(@"Сезон\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private readonly Regex _tvTitleRusEpisodeOfRegex = new(@"(?:Серии|Эпизод|Выпуски)+\s*[:]*\s+(\d+(?:-\d+)?)\s*из\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private readonly Regex _tvTitleRusEpisodeRegex = new(@"(?:Серии|Эпизод|Выпуски)+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private readonly Regex _tvTitleRusSeasonAnimeRegex = new(@"ТВ[-]*(?:(\d+))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private readonly Regex _tvTitleRusEpisodeAnimeOfRegex = new(@"\[(\d+(\+\d+)?)\s+из\s+(\d+(\+\d+)?)\]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public string Parse(string title,
ICollection<IndexerCategory> categories,
@@ -1736,6 +1738,8 @@ namespace NzbDrone.Core.Indexers.Definitions
title = _tvTitleRusSeasonRegex.Replace(title, "S$1");
title = _tvTitleRusEpisodeOfRegex.Replace(title, "E$1 of $2");
title = _tvTitleRusEpisodeRegex.Replace(title, "E$1");
title = _tvTitleRusSeasonAnimeRegex.Replace(title, "S$1");
title = _tvTitleRusEpisodeAnimeOfRegex.Replace(title, "E$1 of $3");
}
else if (IsAnyMovieCategory(categories))
{

View File

@@ -69,8 +69,8 @@ public class Shazbat : TorrentIndexerBase<ShazbatSettings>
.AddFormParameter("referer", "")
.AddFormParameter("query", "")
.AddFormParameter("tv_timezone", "0")
.AddFormParameter("tv_login", Settings.Username)
.AddFormParameter("tv_password", Settings.Password)
.AddFormParameter("username", Settings.Username)
.AddFormParameter("password", Settings.Password)
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
.SetHeader("Referer", loginUrl)
.Build();
@@ -92,9 +92,9 @@ public class Shazbat : TorrentIndexerBase<ShazbatSettings>
_logger.Debug("Authentication succeeded.");
}
protected override bool CheckIfLoginNeeded(HttpResponse response)
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return response.Content.ContainsIgnoreCase("sign in now");
return (httpResponse.HasHttpRedirect && httpResponse.RedirectUrl.ContainsIgnoreCase("login")) || httpResponse.Content.ContainsIgnoreCase("sign in now");
}
private IndexerCapabilities SetCapabilities()
@@ -202,7 +202,7 @@ public class ShazbatRequestGenerator : IIndexerRequestGenerator
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class ShazbatParser : IParseIndexerResponse
public partial class ShazbatParser : IParseIndexerResponse
{
private readonly ProviderDefinition _definition;
private readonly ShazbatSettings _settings;
@@ -210,8 +210,10 @@ public class ShazbatParser : IParseIndexerResponse
private readonly IIndexerHttpClient _httpClient;
private readonly Logger _logger;
private readonly Regex _torrentInfoRegex = new(@"\((?<size>\d+)\):(?<seeders>\d+) \/ :(?<leechers>\d+)$", RegexOptions.Compiled);
private readonly HashSet<string> _hdResolutions = new() { "1080p", "1080i", "720p" };
private readonly HashSet<string> _hdResolutions = ["1080p", "1080i", "720p"];
[GeneratedRegex(@"\((?<size>\d+)\)\s*:(?<seeders>\d+) \/ :(?<leechers>\d+)$", RegexOptions.Compiled)]
private static partial Regex TorrentInfoRegex();
public ShazbatParser(ProviderDefinition definition, ShazbatSettings settings, TimeSpan rateLimit, IIndexerHttpClient httpClient, Logger logger)
{
@@ -278,7 +280,8 @@ public class ShazbatParser : IParseIndexerResponse
var releaseRequest = new IndexerRequest(showRequest);
var releaseResponse = new IndexerResponse(releaseRequest, _httpClient.ExecuteProxied(releaseRequest.HttpRequest, _definition));
if (releaseResponse.HttpResponse.Content.ContainsIgnoreCase("sign in now"))
if ((releaseResponse.HttpResponse.HasHttpRedirect && releaseResponse.HttpResponse.RedirectUrl.ContainsIgnoreCase("login")) ||
releaseResponse.HttpResponse.Content.ContainsIgnoreCase("sign in now"))
{
// Remove cookie cache
CookiesUpdater(null, null);
@@ -324,13 +327,15 @@ public class ShazbatParser : IParseIndexerResponse
var title = ParseTitle(row.QuerySelector("td:nth-of-type(3)"));
var infoString = row.QuerySelector("td:nth-of-type(4)")?.TextContent.Trim() ?? string.Empty;
var matchInfo = _torrentInfoRegex.Match(infoString);
var matchInfo = TorrentInfoRegex().Match(infoString);
var size = matchInfo.Groups["size"].Success && long.TryParse(matchInfo.Groups["size"].Value, out var outSize) ? outSize : 0;
var seeders = matchInfo.Groups["seeders"].Success && int.TryParse(matchInfo.Groups["seeders"].Value, out var outSeeders) ? outSeeders : 0;
var leechers = matchInfo.Groups["leechers"].Success && int.TryParse(matchInfo.Groups["leechers"].Value, out var outLeechers) ? outLeechers : 0;
var dateTimestamp = row.QuerySelector(".datetime[data-timestamp]")?.GetAttribute("data-timestamp");
publishDate = dateTimestamp != null && ParseUtil.TryCoerceDouble(dateTimestamp, out var timestamp) ? DateTimeUtil.UnixTimestampToDateTime(timestamp) : publishDate.AddMinutes(-1);
publishDate = dateTimestamp != null && ParseUtil.TryCoerceLong(dateTimestamp, out var timestamp)
? DateTimeUtil.UnixTimestampToDateTime(timestamp)
: publishDate.AddMinutes(-1);
var release = new TorrentInfo
{
@@ -364,10 +369,10 @@ public class ShazbatParser : IParseIndexerResponse
return title?.TextContent.Trim();
}
protected virtual List<IndexerCategory> ParseCategories(string title)
private List<IndexerCategory> ParseCategories(string title)
{
var categories = new List<IndexerCategory>
{
return
[
NewznabStandardCategory.TV,
title switch
{
@@ -375,9 +380,7 @@ public class ShazbatParser : IParseIndexerResponse
_ when title.Contains("2160p") => NewznabStandardCategory.TVUHD,
_ => NewznabStandardCategory.TVSD
}
};
return categories;
];
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using DryIoc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
@@ -31,6 +32,7 @@ using Prowlarr.Http.ClientSchema;
using Prowlarr.Http.ErrorManagement;
using Prowlarr.Http.Frontend;
using Prowlarr.Http.Middleware;
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace NzbDrone.Host
@@ -59,8 +61,11 @@ namespace NzbDrone.Host
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10));
});
services.AddRouting(options => options.LowercaseUrls = true);