Compare commits

..

7 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
14 changed files with 33 additions and 115 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '2.3.0'
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

@@ -1,18 +1,14 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Label from 'Components/Label';
import Button from 'Components/Link/Button';
import Link from 'Components/Link/Link';
import Menu from 'Components/Menu/Menu';
import MenuContent from 'Components/Menu/MenuContent';
import { kinds, sizes } from 'Helpers/Props';
import { sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AddApplicationPresetMenuItem from './AddApplicationPresetMenuItem';
import styles from './AddApplicationItem.css';
const DEPRECATED_APPLICATIONS = ['Readarr'];
const OBSOLETE_APPLICATIONS = [];
class AddApplicationItem extends Component {
//
@@ -40,8 +36,6 @@ class AddApplicationItem extends Component {
} = this.props;
const hasPresets = !!presets && !!presets.length;
const isDeprecated = DEPRECATED_APPLICATIONS.includes(implementation);
const isObsolete = OBSOLETE_APPLICATIONS.includes(implementation);
return (
<div
@@ -55,24 +49,6 @@ class AddApplicationItem extends Component {
<div className={styles.overlay}>
<div className={styles.name}>
{implementationName}
{
isDeprecated &&
<Label
kind={kinds.WARNING}
title={translate('DeprecatedApplicationMessage', { applicationName: implementationName })}
>
{translate('Deprecated')}
</Label>
}
{
isObsolete &&
<Label
kind={kinds.DANGER}
title={translate('ObsoleteApplicationMessage', { applicationName: implementationName })}
>
{translate('Obsolete')}
</Label>
}
</div>
<div className={styles.actions}>

View File

@@ -10,9 +10,6 @@ import translate from 'Utilities/String/translate';
import EditApplicationModalConnector from './EditApplicationModalConnector';
import styles from './Application.css';
const DEPRECATED_APPLICATIONS = ['Readarr'];
const OBSOLETE_APPLICATIONS = [];
class Application extends Component {
//
@@ -64,13 +61,10 @@ class Application extends Component {
syncLevel,
fields,
tags,
tagList,
implementation
tagList
} = this.props;
const applicationUrl = fields.find((field) => field.name === 'baseUrl')?.value;
const isDeprecated = DEPRECATED_APPLICATIONS.includes(implementation);
const isObsolete = OBSOLETE_APPLICATIONS.includes(implementation);
return (
<Card
@@ -94,26 +88,6 @@ class Application extends Component {
}
</div>
{
isDeprecated &&
<Label
kind={kinds.WARNING}
title={translate('DeprecatedApplicationMessage', { applicationName: implementation })}
>
{translate('Deprecated')}
</Label>
}
{
isObsolete &&
<Label
kind={kinds.DANGER}
title={translate('ObsoleteApplicationMessage', { applicationName: implementation })}
>
{translate('Obsolete')}
</Label>
}
{
syncLevel === 'addOnly' &&
<Label kind={kinds.WARNING}>
@@ -167,7 +141,6 @@ class Application extends Component {
Application.propTypes = {
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
implementation: PropTypes.string.isRequired,
enable: PropTypes.bool.isRequired,
syncLevel: PropTypes.string.isRequired,
fields: PropTypes.arrayOf(PropTypes.object).isRequired,

View File

@@ -39,9 +39,6 @@ const syncLevelOptions = [
}
];
const DEPRECATED_APPLICATIONS = ['Readarr'];
const OBSOLETE_APPLICATIONS = [];
function EditApplicationModalContent(props) {
const {
advancedSettings,
@@ -63,7 +60,6 @@ function EditApplicationModalContent(props) {
const {
id,
implementation,
implementationName,
name,
syncLevel,
@@ -72,9 +68,6 @@ function EditApplicationModalContent(props) {
message
} = item;
const isDeprecated = DEPRECATED_APPLICATIONS.includes(implementation);
const isObsolete = OBSOLETE_APPLICATIONS.includes(implementation);
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
@@ -97,28 +90,6 @@ function EditApplicationModalContent(props) {
{
!isFetching && !error &&
<Form {...otherProps}>
{
isDeprecated &&
<Alert
className={styles.message}
kind={kinds.WARNING}
>
<div>{translate('DeprecatedApplicationTitle', { applicationName: implementationName })}</div>
<div>{translate('DeprecatedApplicationMessage', { applicationName: implementationName })}</div>
</Alert>
}
{
isObsolete &&
<Alert
className={styles.message}
kind={kinds.DANGER}
>
<div>{translate('ObsoleteApplicationTitle', { applicationName: implementationName })}</div>
<div>{translate('ObsoleteApplicationMessage', { applicationName: implementationName })}</div>
</Alert>
}
{
!!message &&
<Alert

View File

@@ -159,7 +159,7 @@ namespace NzbDrone.Core.Applications.Lidarr
case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app");
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break;
}

View File

@@ -172,7 +172,7 @@ namespace NzbDrone.Core.Applications.Radarr
case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app");
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break;
}

View File

@@ -14,7 +14,6 @@ using NzbDrone.Core.Indexers;
namespace NzbDrone.Core.Applications.Readarr
{
[Obsolete("Readarr is deprecated and will be removed in a future version")]
public class Readarr : ApplicationBase<ReadarrSettings>
{
public override string Name => "Readarr";

View File

@@ -146,7 +146,7 @@ namespace NzbDrone.Core.Applications.Readarr
case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app");
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break;
}

View File

@@ -159,7 +159,7 @@ namespace NzbDrone.Core.Applications.Sonarr
case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app");
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break;
}

View File

@@ -144,7 +144,7 @@ namespace NzbDrone.Core.Applications.Whisparr
case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app");
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break;
}

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

@@ -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

@@ -538,12 +538,6 @@
"NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications",
"OAuthPopupMessage": "Pop-ups are being blocked by your browser",
"Obsolete": "Obsolete",
"ObsoleteApplicationMessage": "{applicationName} is obsolete and has been removed",
"ObsoleteApplicationTitle": "{applicationName} is Obsolete",
"Deprecated": "Deprecated",
"DeprecatedApplicationMessage": "{applicationName} is deprecated and will be removed in a future version",
"DeprecatedApplicationTitle": "{applicationName} is Deprecated",
"Ok": "Ok",
"OnApplicationUpdate": "On Application Update",
"OnApplicationUpdateHelpText": "On Application Update",

View File

@@ -64,6 +64,8 @@ namespace NzbDrone.Host
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);