Compare commits

..

10 Commits

Author SHA1 Message Date
Mark McDowall
635e76526a Cleanse console log messages
(cherry picked from commit 609e964794e17343f63e1ecff3fef323e3d284ff)
2025-02-19 15:59:34 +02:00
Stevie Robinson
790feed5ab Fixed: Fallback to Instance Name for Discord notifications
(cherry picked from commit b99e06acc0a3ecae2857d9225b35424c82c67a2b)
2025-02-19 15:55:42 +02:00
Mark McDowall
59b5d2fc78 Fixed: Drop downs flickering in some cases
(cherry picked from commit 3b024443c5447b7638a69a99809bf44b2419261f)
2025-02-18 17:09:56 +02:00
Bogdan
d5b12cf51a Fixed release guid for SpeedApp 2025-02-18 04:00:24 +02:00
Bogdan
2d584f7eb6 New: Support for exclusive indexer flag
Co-authored-by: zakkarry <zak@ary.dev>
2025-02-18 02:11:57 +02:00
Bogdan
0f1d647cd7 Fixed: (FileList) Download links when passkey contains spaces 2025-02-16 12:22:44 +02:00
zodihax
d6e8d89be4 Fixed: (NorBits) Update release category parsing (#2342)
Co-authored-by: Bogdan <mynameisbogdan@users.noreply.github.com>
2025-02-12 19:27:09 +02:00
Bogdan
8672129d5a Fixed: (AnimeTorrents) Switched to cookies login 2025-02-12 15:52:22 +02:00
Bogdan
44bdff8b8f Minor cleanup for AnimeTorrents 2025-02-12 15:52:22 +02:00
Bogdan
4df8fc02f1 Bump version to 1.31.2 2025-02-09 17:51:35 +02:00
19 changed files with 232 additions and 230 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.31.1'
majorVersion: '1.31.2'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'

View File

@@ -20,6 +20,8 @@ import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
import TextInput from './TextInput';
import styles from './EnhancedSelectInput.css';
const MINIMUM_DISTANCE_FROM_EDGE = 10;
function isArrowKey(keyCode) {
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
}
@@ -137,18 +139,9 @@ class EnhancedSelectInput extends Component {
// Listeners
onComputeMaxHeight = (data) => {
const {
top,
bottom
} = data.offsets.reference;
const windowHeight = window.innerHeight;
if ((/^botton/).test(data.placement)) {
data.styles.maxHeight = windowHeight - bottom;
} else {
data.styles.maxHeight = top;
}
data.styles.maxHeight = windowHeight - MINIMUM_DISTANCE_FROM_EDGE;
return data;
};
@@ -460,6 +453,10 @@ class EnhancedSelectInput extends Component {
order: 851,
enabled: true,
fn: this.onComputeMaxHeight
},
preventOverflow: {
enabled: true,
boundariesElement: 'viewport'
}
}}
>

View File

@@ -0,0 +1,21 @@
using System.Text;
using NLog;
using NLog.Layouts.ClefJsonLayout;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation;
public class CleansingClefLogLayout : CompactJsonLayout
{
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
base.RenderFormattedMessage(logEvent, target);
if (RuntimeInfo.IsProduction)
{
var result = CleanseLogMessage.Cleanse(target.ToString());
target.Clear();
target.Append(result);
}
}
}

View File

@@ -0,0 +1,26 @@
using System.Text;
using NLog;
using NLog.Layouts;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation;
public class CleansingConsoleLogLayout : SimpleLayout
{
public CleansingConsoleLogLayout(string format)
: base(format)
{
}
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
base.RenderFormattedMessage(logEvent, target);
if (RuntimeInfo.IsProduction)
{
var result = CleanseLogMessage.Cleanse(target.ToString());
target.Clear();
target.Append(result);
}
}
}

View File

@@ -4,7 +4,7 @@ using NLog.Targets;
namespace NzbDrone.Common.Instrumentation
{
public class NzbDroneFileTarget : FileTarget
public class CleansingFileTarget : FileTarget
{
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{

View File

@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.IO;
using NLog;
using NLog.Config;
using NLog.Layouts.ClefJsonLayout;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
@@ -13,9 +12,11 @@ namespace NzbDrone.Common.Instrumentation
{
public static class NzbDroneLogger
{
private const string FILE_LOG_LAYOUT = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
public const string ConsoleLogLayout = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
public static CompactJsonLayout ClefLogLayout = new CompactJsonLayout();
private const string FileLogLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
private const string ConsoleFormat = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
private static readonly CleansingConsoleLogLayout CleansingConsoleLayout = new (ConsoleFormat);
private static readonly CleansingClefLogLayout ClefLogLayout = new ();
private static bool _isConfigured;
@@ -119,11 +120,7 @@ namespace NzbDrone.Common.Instrumentation
? formatEnumValue
: ConsoleLogFormat.Standard;
coloredConsoleTarget.Layout = logFormat switch
{
ConsoleLogFormat.Clef => ClefLogLayout,
_ => ConsoleLogLayout
};
ConfigureConsoleLayout(coloredConsoleTarget, logFormat);
var loggingRule = new LoggingRule("*", level, coloredConsoleTarget);
@@ -140,7 +137,7 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)
{
var fileTarget = new NzbDroneFileTarget();
var fileTarget = new CleansingFileTarget();
fileTarget.Name = name;
fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), fileName);
@@ -153,7 +150,7 @@ namespace NzbDrone.Common.Instrumentation
fileTarget.MaxArchiveFiles = maxArchiveFiles;
fileTarget.EnableFileDelete = true;
fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
fileTarget.Layout = FILE_LOG_LAYOUT;
fileTarget.Layout = FileLogLayout;
var loggingRule = new LoggingRule("*", minLogLevel, fileTarget);
@@ -172,7 +169,7 @@ namespace NzbDrone.Common.Instrumentation
fileTarget.ConcurrentWrites = false;
fileTarget.ConcurrentWriteAttemptDelay = 50;
fileTarget.ConcurrentWriteAttempts = 100;
fileTarget.Layout = FILE_LOG_LAYOUT;
fileTarget.Layout = FileLogLayout;
var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget);
@@ -217,6 +214,15 @@ namespace NzbDrone.Common.Instrumentation
{
return GetLogger(obj.GetType());
}
public static void ConfigureConsoleLayout(ColoredConsoleTarget target, ConsoleLogFormat format)
{
target.Layout = format switch
{
ConsoleLogFormat.Clef => NzbDroneLogger.ClefLogLayout,
_ => NzbDroneLogger.CleansingConsoleLayout
};
}
}
public enum ConsoleLogFormat

View File

@@ -26,15 +26,15 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
Subject.Definition = new IndexerDefinition
{
Name = "HdBits",
Settings = new HDBitsSettings() { ApiKey = "fakekey" }
Settings = new HDBitsSettings { ApiKey = "fakekey" }
};
_movieSearchCriteria = new MovieSearchCriteria
{
Categories = new int[] { 2000, 2010 },
Categories = new[] { 2000, 2010 },
ImdbId = "0076759"
};
}
@@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases;
torrents.Should().HaveCount(2);
torrents.First().Should().BeOfType<HDBitsInfo>();
torrents.First().Should().BeOfType<TorrentInfo>();
var first = torrents.First() as TorrentInfo;

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using NLog;
using NzbDrone.Common.Extensions;
@@ -44,46 +43,19 @@ namespace NzbDrone.Core.Indexers.Definitions
return new AnimeTorrentsParser(Settings, Capabilities.Categories);
}
protected override async Task DoLogin()
{
UpdateCookies(null, null);
var loginUrl = Settings.BaseUrl + "login.php";
var loginPage = await ExecuteAuth(new HttpRequest(loginUrl));
var requestBuilder = new HttpRequestBuilder(loginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true
};
var authLoginRequest = requestBuilder
.Post()
.SetCookies(loginPage.GetCookies())
.AddFormParameter("username", Settings.Username)
.AddFormParameter("password", Settings.Password)
.AddFormParameter("form", "login")
.AddFormParameter("rememberme[]", "1")
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
.SetHeader("Referer", loginUrl)
.Build();
var response = await ExecuteAuth(authLoginRequest);
if (response.Content == null || !response.Content.Contains("logout.php"))
{
throw new IndexerAuthException("AnimeTorrents authentication failed");
}
UpdateCookies(response.GetCookies(), DateTime.Now.AddDays(30));
_logger.Debug("AnimeTorrents authentication succeeded");
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return httpResponse.Content.Contains("Access Denied!") || httpResponse.Content.Contains("login.php");
if (httpResponse.Content.Contains("Access Denied!") || httpResponse.Content.Contains("login.php"))
{
throw new IndexerAuthException("AnimeTorrents authentication with cookies failed.");
}
return false;
}
protected override IDictionary<string, string> GetCookies()
{
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
}
private IndexerCapabilities SetCapabilities()
@@ -292,7 +264,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var qTitleLink = row.QuerySelector("td:nth-of-type(2) a:nth-of-type(1)");
var title = qTitleLink?.TextContent.Trim();
// If we search an get no results, we still get a table just with no info.
// If we search and get no results, we still get a table just with no info.
if (title.IsNullOrWhiteSpace())
{
break;
@@ -307,6 +279,8 @@ namespace NzbDrone.Core.Indexers.Definitions
var connections = row.QuerySelector("td:nth-of-type(8)").TextContent.Trim().Split('/', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
var seeders = ParseUtil.CoerceInt(connections[0]);
var leechers = ParseUtil.CoerceInt(connections[1]);
var grabs = ParseUtil.CoerceInt(connections[2]);
var categoryLink = row.QuerySelector("td:nth-of-type(1) a")?.GetAttribute("href") ?? string.Empty;
var categoryId = ParseUtil.GetArgumentFromQueryString(categoryLink, "cat");
@@ -328,17 +302,17 @@ namespace NzbDrone.Core.Indexers.Definitions
PublishDate = publishedDate,
Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-of-type(6)").TextContent.Trim()),
Seeders = seeders,
Peers = ParseUtil.CoerceInt(connections[1]) + seeders,
Grabs = ParseUtil.CoerceInt(connections[2]),
Peers = leechers + seeders,
Grabs = grabs,
DownloadVolumeFactor = downloadVolumeFactor,
UploadVolumeFactor = 1,
Genres = row.QuerySelectorAll("td:nth-of-type(2) a.tortags").Select(t => t.TextContent.Trim()).ToList()
};
var uLFactorImg = row.QuerySelector("img[alt*=\"x Multiplier Torrent\"]");
if (uLFactorImg != null)
var uploadFactor = row.QuerySelector("img[alt*=\"x Multiplier Torrent\"]")?.GetAttribute("alt");
if (uploadFactor != null)
{
release.UploadVolumeFactor = ParseUtil.CoerceDouble(uLFactorImg.GetAttribute("alt").Split('x')[0]);
release.UploadVolumeFactor = ParseUtil.CoerceDouble(uploadFactor.Split('x')[0]);
}
releaseInfos.Add(release);
@@ -350,7 +324,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class AnimeTorrentsSettings : UserPassTorrentBaseSettings
public class AnimeTorrentsSettings : CookieTorrentBaseSettings
{
public AnimeTorrentsSettings()
{
@@ -361,7 +335,7 @@ namespace NzbDrone.Core.Indexers.Definitions
[FieldDefinition(4, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Show freeleech torrents only")]
public bool FreeleechOnly { get; set; }
[FieldDefinition(5, Label = "Downloadable Only", Type = FieldType.Checkbox, HelpText = "Search downloadable torrents only (enable this only if your account class is Newbie)")]
[FieldDefinition(5, Label = "Downloadable Only", Type = FieldType.Checkbox, HelpText = "Search downloadable torrents only (enable this only if your account class is Newbie)", Advanced = true)]
public bool DownloadableOnly { get; set; }
}
}

View File

@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
private IndexerCapabilities SetCapabilities()
private static IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
@@ -69,7 +69,8 @@ namespace NzbDrone.Core.Indexers.Definitions
},
Flags = new List<IndexerFlag>
{
IndexerFlag.Internal
IndexerFlag.Internal,
IndexerFlag.Exclusive,
}
};
@@ -275,13 +276,6 @@ namespace NzbDrone.Core.Indexers.Definitions
var details = row.InfoUrl;
var link = row.DownloadLink;
var flags = new HashSet<IndexerFlag>();
if (row.Internal)
{
flags.Add(IndexerFlag.Internal);
}
var release = new TorrentInfo
{
Title = row.Name,
@@ -291,7 +285,7 @@ namespace NzbDrone.Core.Indexers.Definitions
Guid = details,
Categories = _categories.MapTrackerCatDescToNewznab(row.Category),
PublishDate = DateTime.Parse(row.CreatedAt, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
IndexerFlags = flags,
IndexerFlags = GetIndexerFlags(row),
Size = row.Size,
Grabs = row.Grabs,
Seeders = row.Seeders,
@@ -319,6 +313,23 @@ namespace NzbDrone.Core.Indexers.Definitions
.ToArray();
}
private static HashSet<IndexerFlag> GetIndexerFlags(BeyondHDTorrent item)
{
var flags = new HashSet<IndexerFlag>();
if (item.Internal)
{
flags.Add(IndexerFlag.Internal);
}
if (item.Exclusive)
{
flags.Add(IndexerFlag.Exclusive);
}
return flags;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
@@ -478,6 +489,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public bool Limited { get; set; }
public bool Exclusive { get; set; }
public bool Internal { get; set; }
}
}

View File

@@ -101,7 +101,7 @@ public class FileListParser : IParseIndexerResponse
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/download.php")
.AddQueryParam("id", torrentId.ToString())
.AddQueryParam("passkey", _settings.Passkey);
.AddQueryParam("passkey", _settings.Passkey.Trim());
return url.FullUri;
}

View File

@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
return new HDBitsParser(Settings, Capabilities.Categories);
}
private IndexerCapabilities SetCapabilities()
private static IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
@@ -43,6 +43,11 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
Flags = new List<IndexerFlag>
{
IndexerFlag.Internal,
IndexerFlag.Exclusive,
}
};

View File

@@ -85,6 +85,9 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
[JsonProperty(PropertyName = "type_origin")]
public int TypeOrigin { get; set; }
[JsonProperty(PropertyName = "type_exclusive")]
public int TypeExclusive { get; set; }
[JsonProperty(PropertyName = "imdb")]
public ImdbInfo ImdbInfo { get; set; }

View File

@@ -1,9 +0,0 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.HDBits
{
public class HDBitsInfo : TorrentInfo
{
public bool? Internal { get; set; }
}
}

View File

@@ -62,16 +62,8 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
}
var id = result.Id;
var internalRelease = result.TypeOrigin == 1;
var flags = new HashSet<IndexerFlag>();
if (internalRelease)
{
flags.Add(IndexerFlag.Internal);
}
releaseInfos.Add(new HDBitsInfo
releaseInfos.Add(new TorrentInfo
{
Guid = $"HDBits-{id}",
Title = GetTitle(result),
@@ -85,21 +77,18 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
Files = (int)result.NumFiles,
Peers = result.Leechers + result.Seeders,
PublishDate = result.Added.ToUniversalTime(),
Internal = internalRelease,
Year = result.ImdbInfo?.Year ?? 0,
ImdbId = result.ImdbInfo?.Id ?? 0,
TvdbId = result.TvdbInfo?.Id ?? 0,
DownloadVolumeFactor = GetDownloadVolumeFactor(result),
UploadVolumeFactor = GetUploadVolumeFactor(result),
IndexerFlags = flags
IndexerFlags = GetIndexerFlags(result)
});
}
return releaseInfos.ToArray();
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private string GetTitle(TorrentQueryResponse item)
{
// Use release name for XXX content and full discs
@@ -108,6 +97,23 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
: item.Name;
}
private static HashSet<IndexerFlag> GetIndexerFlags(TorrentQueryResponse item)
{
var flags = new HashSet<IndexerFlag>();
if (item.TypeOrigin == 1)
{
flags.Add(IndexerFlag.Internal);
}
if (item.TypeExclusive == 1)
{
flags.Add(IndexerFlag.Exclusive);
}
return flags;
}
private double GetDownloadVolumeFactor(TorrentQueryResponse item)
{
if (item.FreeLeech == "yes")
@@ -154,5 +160,7 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
return url.FullUri;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
}

View File

@@ -130,29 +130,13 @@ public class NorBits : TorrentIndexerBase<NorBitsSettings>
};
caps.Categories.AddCategoryMapping("main_cat[]=1", NewznabStandardCategory.Movies, "Filmer");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=49", NewznabStandardCategory.MoviesUHD, "Filmer - UHD-2160p");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", NewznabStandardCategory.MoviesHD, "Filmer - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", NewznabStandardCategory.MoviesHD, "Filmer - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", NewznabStandardCategory.MoviesSD, "Filmer - SD");
caps.Categories.AddCategoryMapping("main_cat[]=2", NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=49", NewznabStandardCategory.TVUHD, "TV - UHD-2160p");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", NewznabStandardCategory.TVHD, "TV - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", NewznabStandardCategory.TVHD, "TV - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", NewznabStandardCategory.TVSD, "TV - SD");
caps.Categories.AddCategoryMapping("main_cat[]=3", NewznabStandardCategory.PC, "Programmer");
caps.Categories.AddCategoryMapping("main_cat[]=4", NewznabStandardCategory.Console, "Spill");
caps.Categories.AddCategoryMapping("main_cat[]=5", NewznabStandardCategory.Audio, "Musikk");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", NewznabStandardCategory.AudioMP3, "Musikk - 192");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", NewznabStandardCategory.AudioMP3, "Musikk - 256");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", NewznabStandardCategory.AudioMP3, "Musikk - 320");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", NewznabStandardCategory.AudioMP3, "Musikk - VBR");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", NewznabStandardCategory.AudioLossless, "Musikk - Lossless");
caps.Categories.AddCategoryMapping("main_cat[]=6", NewznabStandardCategory.Books, "Tidsskrift");
caps.Categories.AddCategoryMapping("main_cat[]=7", NewznabStandardCategory.AudioAudiobook, "Lydbøker");
caps.Categories.AddCategoryMapping("main_cat[]=8", NewznabStandardCategory.AudioVideo, "Musikkvideoer");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", NewznabStandardCategory.AudioVideo, "Musikkvideoer - SD");
caps.Categories.AddCategoryMapping("main_cat[]=40", NewznabStandardCategory.AudioOther, "Podcasts");
return caps;
@@ -281,20 +265,17 @@ public class NorBitsParser : IParseIndexerResponse
foreach (var row in rows)
{
var link = _settings.BaseUrl + row.QuerySelector("td:nth-of-type(2) > a[href*=\"download.php?id=\"]")?.GetAttribute("href").TrimStart('/');
var link = _settings.BaseUrl + row.QuerySelector("td:nth-of-type(2) > a[href*=\"download.php?id=\"]")?.GetAttribute("href")?.TrimStart('/');
var qDetails = row.QuerySelector("td:nth-of-type(2) > a[href*=\"details.php?id=\"]");
var title = qDetails?.GetAttribute("title").Trim();
var details = _settings.BaseUrl + qDetails?.GetAttribute("href").TrimStart('/');
var title = qDetails?.GetAttribute("title")?.Trim();
var details = _settings.BaseUrl + qDetails?.GetAttribute("href")?.TrimStart('/');
var mainCategory = row.QuerySelector("td:nth-of-type(1) a[href*=\"main_cat[]\"]")?.GetAttribute("href")?.Split('?').Last();
var secondCategory = row.QuerySelector("td:nth-of-type(1) a[href*=\"sub2_cat[]\"]")?.GetAttribute("href")?.Split('?').Last();
var catQuery = row.QuerySelector("td:nth-of-type(1) a[href*=\"main_cat[]\"]")?.GetAttribute("href")?.Split('?').Last().Split('&', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var category = catQuery?.FirstOrDefault(x => x.StartsWith("main_cat[]=", StringComparison.OrdinalIgnoreCase));
var categoryList = new[] { mainCategory, secondCategory };
var cat = string.Join("&", categoryList.Where(c => !string.IsNullOrWhiteSpace(c)));
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent);
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent);
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)")?.TextContent);
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)")?.TextContent);
var release = new TorrentInfo
{
@@ -302,7 +283,7 @@ public class NorBitsParser : IParseIndexerResponse
InfoUrl = details,
DownloadUrl = link,
Title = title,
Categories = _categories.MapTrackerCatToNewznab(cat),
Categories = _categories.MapTrackerCatToNewznab(category),
Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-of-type(7)")?.TextContent),
Files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(3) > a")?.TextContent.Trim()),
Grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)")?.FirstChild?.TextContent.Trim()),

View File

@@ -262,7 +262,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return jsonResponse.Resource.Select(torrent => new TorrentInfo
{
Guid = torrent.Id.ToString(),
Guid = torrent.Url,
Title = CleanTitle(torrent.Name),
Description = torrent.ShortDescription,
Size = torrent.Size,

View File

@@ -63,6 +63,7 @@ namespace NzbDrone.Core.Indexers
}
public static IndexerFlag Internal => new ("internal", "Uploader is an internal release group");
public static IndexerFlag Exclusive => new ("exclusive", "An exclusive release that must not be uploaded anywhere else");
public static IndexerFlag FreeLeech => new ("freeleech", "Download doesn't count toward ratio");
public static IndexerFlag NeutralLeech => new ("neutralleech", "Download and upload doesn't count toward ratio");
public static IndexerFlag HalfLeech => new ("halfleech", "Release counts 50% to ratio");

View File

@@ -95,7 +95,7 @@ namespace NzbDrone.Core.Instrumentation
private void ReconfigureFile()
{
foreach (var target in LogManager.Configuration.AllTargets.OfType<NzbDroneFileTarget>())
foreach (var target in LogManager.Configuration.AllTargets.OfType<CleansingFileTarget>())
{
target.MaxArchiveFiles = _configFileProvider.LogRotate;
target.ArchiveAboveSize = _configFileProvider.LogSizeLimit.Megabytes();
@@ -120,11 +120,7 @@ namespace NzbDrone.Core.Instrumentation
{
var format = _configFileProvider.ConsoleLogFormat;
consoleTarget.Layout = format switch
{
ConsoleLogFormat.Clef => NzbDroneLogger.ClefLogLayout,
_ => NzbDroneLogger.ConsoleLogLayout
};
NzbDroneLogger.ConfigureConsoleLayout(consoleTarget, format);
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Notifications.Discord.Payloads;
using NzbDrone.Core.Validation;
@@ -10,10 +11,12 @@ namespace NzbDrone.Core.Notifications.Discord
public class Discord : NotificationBase<DiscordSettings>
{
private readonly IDiscordProxy _proxy;
private readonly IConfigFileProvider _configFileProvider;
public Discord(IDiscordProxy proxy)
public Discord(IDiscordProxy proxy, IConfigFileProvider configFileProvider)
{
_proxy = proxy;
_configFileProvider = configFileProvider;
}
public override string Name => "Discord";
@@ -22,18 +25,18 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnGrab(GrabMessage message)
{
var embed = new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = RELEASE_GRABBED_TITLE,
Description = message.Message,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = message.Successful ? (int)DiscordColors.Success : (int)DiscordColors.Danger,
Fields = new List<DiscordField>()
};
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? _configFileProvider.InstanceName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = RELEASE_GRABBED_TITLE,
Description = message.Message,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = message.Successful ? (int)DiscordColors.Success : (int)DiscordColors.Danger,
Fields = new List<DiscordField>()
};
foreach (var field in Settings.GrabFields)
{
@@ -80,81 +83,72 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
{
var attachments = new List<Embed>
{
new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = healthCheck.Source.Name,
Description = healthCheck.Message,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = healthCheck.Type == HealthCheck.HealthCheckResult.Warning ? (int)DiscordColors.Warning : (int)DiscordColors.Danger
}
};
var embed = new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? _configFileProvider.InstanceName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = healthCheck.Source.Name,
Description = healthCheck.Message,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = healthCheck.Type == HealthCheck.HealthCheckResult.Warning ? (int)DiscordColors.Warning : (int)DiscordColors.Danger
};
var payload = CreatePayload(null, attachments);
var payload = CreatePayload(null, new List<Embed> { embed });
_proxy.SendPayload(payload, Settings);
}
public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck)
{
var attachments = new List<Embed>
{
new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = "Health Issue Resolved: " + previousCheck.Source.Name,
Description = $"The following issue is now resolved: {previousCheck.Message}",
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Success
}
};
var embed = new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? _configFileProvider.InstanceName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = "Health Issue Resolved: " + previousCheck.Source.Name,
Description = $"The following issue is now resolved: {previousCheck.Message}",
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Success
};
var payload = CreatePayload(null, attachments);
var payload = CreatePayload(null, new List<Embed> { embed });
_proxy.SendPayload(payload, Settings);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
var attachments = new List<Embed>
{
new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = APPLICATION_UPDATE_TITLE,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Standard,
Fields = new List<DiscordField>()
{
new DiscordField()
{
Name = "Previous Version",
Value = updateMessage.PreviousVersion.ToString()
},
new DiscordField()
{
Name = "New Version",
Value = updateMessage.NewVersion.ToString()
}
},
}
};
var embed = new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? _configFileProvider.InstanceName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = APPLICATION_UPDATE_TITLE,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Standard,
Fields = new List<DiscordField>
{
new ()
{
Name = "Previous Version",
Value = updateMessage.PreviousVersion.ToString()
},
new ()
{
Name = "New Version",
Value = updateMessage.NewVersion.ToString()
}
},
};
var payload = CreatePayload(null, attachments);
var payload = CreatePayload(null, new List<Embed> { embed });
_proxy.SendPayload(payload, Settings);
}
@@ -208,19 +202,5 @@ namespace NzbDrone.Core.Notifications.Discord
return payload;
}
private static string BytesToString(long byteCount)
{
string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
if (byteCount == 0)
{
return "0 " + suf[0];
}
var bytes = Math.Abs(byteCount);
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
var num = Math.Round(bytes / Math.Pow(1024, place), 1);
return string.Format("{0} {1}", (Math.Sign(byteCount) * num).ToString(), suf[place]);
}
}
}